From: Dave Chinner <dchinner@xxxxxxxxxx> Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> --- db/sb.c | 1 + include/libxfs.h | 5 ++ include/xfs_alloc_btree.h | 2 +- include/xfs_bmap_btree.h | 2 +- include/xfs_btree.h | 5 +- include/xfs_ialloc_btree.h | 2 +- include/xfs_symlink.h | 2 + libxfs/rdwr.c | 20 ++++- libxfs/xfs.h | 12 ++- libxfs/xfs_alloc.c | 7 +- libxfs/xfs_btree.c | 20 +++-- libxfs/xfs_ialloc.c | 2 - libxfs/xfs_mount.c | 16 ---- libxlog/xfs_log_recover.c | 4 +- logprint/logprint.c | 3 + repair/agheader.c | 36 ++++++++- repair/dino_chunks.c | 7 +- repair/dinode.c | 190 ++++++++++++++++++++++++++------------------ repair/phase2.c | 1 + repair/phase5.c | 157 +++++++++++++++++++++++++++--------- repair/prefetch.c | 7 +- repair/scan.c | 158 +++++++++++++++++++----------------- repair/scan.h | 12 ++- repair/versions.c | 2 +- repair/xfs_repair.c | 2 +- 25 files changed, 435 insertions(+), 240 deletions(-) diff --git a/db/sb.c b/db/sb.c index f99210c..af86722 100644 --- a/db/sb.c +++ b/db/sb.c @@ -240,6 +240,7 @@ sb_logcheck(void) log.l_logsize = BBTOB(log.l_logBBsize); log.l_logBBsize = x.logBBsize; log.l_logBBstart = x.logBBstart; + log.l_sectBBsize = x.lbsize; log.l_mp = mp; if (xlog_find_tail(&log, &head_blk, &tail_blk)) { diff --git a/include/libxfs.h b/include/libxfs.h index f64e489..e6cae94 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -678,6 +678,7 @@ void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); #define libxfs_dinode_to_disk xfs_dinode_to_disk void xfs_dinode_from_disk(struct xfs_icdinode *, struct xfs_dinode *); +#define libxfs_dinode_calc_crc xfs_dinode_calc_crc #define libxfs_idata_realloc xfs_idata_realloc #define libxfs_idestroy_fork xfs_idestroy_fork @@ -686,6 +687,10 @@ void xfs_dinode_from_disk(struct xfs_icdinode *, #define libxfs_sb_from_disk xfs_sb_from_disk #define libxfs_sb_to_disk xfs_sb_to_disk +/* xfs_symlink.h */ +#define libxfs_symlink_blocks xfs_symlink_blocks +#define libxfs_symlink_hdr_ok xfs_symlink_hdr_ok + /* xfs_rtalloc.c */ int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t); diff --git a/include/xfs_alloc_btree.h b/include/xfs_alloc_btree.h index 6968494..5cf27ec 100644 --- a/include/xfs_alloc_btree.h +++ b/include/xfs_alloc_btree.h @@ -64,7 +64,7 @@ typedef __be32 xfs_alloc_ptr_t; */ #define XFS_ALLOC_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \ + XFS_BTREE_SBLOCK_CRC_LEN : \ XFS_BTREE_SBLOCK_LEN) /* diff --git a/include/xfs_bmap_btree.h b/include/xfs_bmap_btree.h index 2dd3a1a..b54cc0c 100644 --- a/include/xfs_bmap_btree.h +++ b/include/xfs_bmap_btree.h @@ -140,7 +140,7 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; */ #define XFS_BMBT_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - XFS_BTREE_LBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \ + XFS_BTREE_LBLOCK_CRC_LEN : \ XFS_BTREE_LBLOCK_LEN) #define XFS_BMBT_REC_ADDR(mp, block, index) \ diff --git a/include/xfs_btree.h b/include/xfs_btree.h index 02f89d8..c0acbbf 100644 --- a/include/xfs_btree.h +++ b/include/xfs_btree.h @@ -83,7 +83,10 @@ struct xfs_btree_block { #define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */ #define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */ -#define XFS_BTREE_CRCBLOCK_ADD 32 /* size of blkno + crc + uuid */ + +/* sizes of CRC enabled btree blocks */ +#define XFS_BTREE_SBLOCK_CRC_LEN (XFS_BTREE_SBLOCK_LEN + 40) +#define XFS_BTREE_LBLOCK_CRC_LEN (XFS_BTREE_LBLOCK_LEN + 48) #define XFS_BTREE_SBLOCK_CRC_OFF \ offsetof(struct xfs_btree_block, bb_u.s.bb_crc) diff --git a/include/xfs_ialloc_btree.h b/include/xfs_ialloc_btree.h index 96fb140..2efbd91 100644 --- a/include/xfs_ialloc_btree.h +++ b/include/xfs_ialloc_btree.h @@ -80,7 +80,7 @@ typedef __be32 xfs_inobt_ptr_t; */ #define XFS_INOBT_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \ + XFS_BTREE_SBLOCK_CRC_LEN : \ XFS_BTREE_SBLOCK_LEN) /* diff --git a/include/xfs_symlink.h b/include/xfs_symlink.h index bb21e6a..55f3f2d 100644 --- a/include/xfs_symlink.h +++ b/include/xfs_symlink.h @@ -29,6 +29,8 @@ struct xfs_dsymlink_hdr { sizeof(struct xfs_dsymlink_hdr) : 0)) int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); +bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, + uint32_t size, struct xfs_buf *bp); extern const struct xfs_buf_ops xfs_symlink_buf_ops; diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 0629d50..ee7702c 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -444,6 +444,7 @@ __libxfs_getbufr(int blen) } else bp = kmem_zone_zalloc(xfs_buf_zone, 0); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); + bp->b_ops = NULL; return bp; } @@ -700,6 +701,7 @@ libxfs_readbuf(struct xfs_buftarg dev, xfs_daddr_t blkno, int len, int flags, bp = libxfs_getbuf(dev, blkno, len); if (!bp) return NULL; + bp->b_error = 0; bp->b_ops = ops; if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) return bp; @@ -795,10 +797,20 @@ libxfs_writebufr(xfs_buf_t *bp) int fd = libxfs_device_to_fd(bp->b_target.dev); int error = 0; + /* + * clear any pre-existing error status on the buffer. This can occur if + * the buffer is corrupt on disk and the repair process doesn't clear + * the error before fixing and writing it back. + */ + bp->b_error = 0; if (bp->b_ops) { bp->b_ops->verify_write(bp); - if (bp->b_error) + if (bp->b_error) { + fprintf(stderr, + _("%s: write verifer failed on bno 0x%llx/0x%x\n"), + __func__, (long long)bp->b_bn, bp->b_bcount); return error; + } } if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) { @@ -845,6 +857,12 @@ libxfs_writebuf_int(xfs_buf_t *bp, int flags) int libxfs_writebuf(xfs_buf_t *bp, int flags) { +#ifdef IO_DEBUG + printf("%lx: %s: dirty blkno=%llu(%llu)\n", + pthread_self(), __FUNCTION__, + (long long)LIBXFS_BBTOOFF64(bp->b_bn), + (long long)bp->b_bn); +#endif bp->b_flags |= (LIBXFS_B_DIRTY | flags); libxfs_putbuf(bp); return 0; diff --git a/libxfs/xfs.h b/libxfs/xfs.h index 398e48c..74617d1 100644 --- a/libxfs/xfs.h +++ b/libxfs/xfs.h @@ -76,8 +76,16 @@ typedef __uint32_t inst_t; /* an instruction */ #define IHOLD(ip) ((void) 0) /* stop unused var warnings by assigning mp to itself */ -#define XFS_CORRUPTION_ERROR(e,l,mp,m) do { (mp) = (mp); } while (0) -#define XFS_ERROR_REPORT(e,l,mp) do { (mp) = (mp); } while (0) +#define XFS_CORRUPTION_ERROR(e,l,mp,m) do { \ + (mp) = (mp); \ + cmn_err(CE_ALERT, "%s: XFS_CORRUPTION_ERROR", (e)); \ +} while (0) + +#define XFS_ERROR_REPORT(e,l,mp) do { \ + (mp) = (mp); \ + cmn_err(CE_ALERT, "%s: XFS_ERROR_REPORT", (e)); \ +} while (0) + #define XFS_QM_DQATTACH(mp,ip,flags) 0 #define XFS_ERROR(e) (e) #define XFS_ERRLEVEL_LOW 1 diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c index bc9995d..df36435 100644 --- a/libxfs/xfs_alloc.c +++ b/libxfs/xfs_alloc.c @@ -2173,8 +2173,13 @@ xfs_agf_verify( struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); if (xfs_sb_version_hascrc(&mp->m_sb) && - !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_uuid)) + !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_uuid)) { + char uu[64], uu2[64]; + platform_uuid_unparse(&agf->agf_uuid, uu); + platform_uuid_unparse(&mp->m_sb.sb_uuid, uu2); + return false; + } if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c index 0d36584..219d154 100644 --- a/libxfs/xfs_btree.c +++ b/libxfs/xfs_btree.c @@ -391,17 +391,15 @@ xfs_btree_dup_cursor( */ static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur) { - size_t len; - - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - len = XFS_BTREE_LBLOCK_LEN; - else - len = XFS_BTREE_SBLOCK_LEN; + if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { + if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) + return XFS_BTREE_LBLOCK_CRC_LEN; + return XFS_BTREE_LBLOCK_LEN; + } if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) - len += XFS_BTREE_CRCBLOCK_ADD; - - return len; + return XFS_BTREE_SBLOCK_CRC_LEN; + return XFS_BTREE_SBLOCK_LEN; } /* @@ -1311,7 +1309,7 @@ xfs_btree_log_block( offsetof(struct xfs_btree_block, bb_u.s.bb_uuid), offsetof(struct xfs_btree_block, bb_u.s.bb_owner), offsetof(struct xfs_btree_block, bb_u.s.bb_crc), - XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD + XFS_BTREE_SBLOCK_CRC_LEN }; static const short loffsets[] = { /* table of offsets (long) */ offsetof(struct xfs_btree_block, bb_magic), @@ -1325,7 +1323,7 @@ xfs_btree_log_block( offsetof(struct xfs_btree_block, bb_u.l.bb_owner), offsetof(struct xfs_btree_block, bb_u.l.bb_crc), offsetof(struct xfs_btree_block, bb_u.l.bb_pad), - XFS_BTREE_LBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD + XFS_BTREE_LBLOCK_CRC_LEN }; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c index 5e49a7d..400fb1d 100644 --- a/libxfs/xfs_ialloc.c +++ b/libxfs/xfs_ialloc.c @@ -182,8 +182,6 @@ xfs_ialloc_inode_init( ino = XFS_AGINO_TO_INO(mp, agno, XFS_OFFBNO_TO_AGINO(mp, agbno, 0)); } else if (xfs_sb_version_hasnlink(&mp->m_sb)) - version = 3; - else if (xfs_sb_version_hasnlink(&mp->m_sb)) version = 2; else version = 1; diff --git a/libxfs/xfs_mount.c b/libxfs/xfs_mount.c index 6ff2773..95e6726 100644 --- a/libxfs/xfs_mount.c +++ b/libxfs/xfs_mount.c @@ -141,22 +141,6 @@ xfs_mount_validate_sb( return XFS_ERROR(EWRONGFS); } - if (unlikely( - sbp->sb_logstart == 0 && mp->m_logdev.dev == mp->m_dev.dev)) { - xfs_warn(mp, - "filesystem is marked as having an external log; " - "specify logdev on the mount command line."); - return XFS_ERROR(EINVAL); - } - - if (unlikely( - sbp->sb_logstart != 0 && mp->m_logdev.dev != mp->m_dev.dev)) { - xfs_warn(mp, - "filesystem is marked as having an internal log; " - "do not specify logdev on the mount command line."); - return XFS_ERROR(EINVAL); - } - /* * More sanity checking. Most of these were stolen directly from * xfs_repair. diff --git a/libxlog/xfs_log_recover.c b/libxlog/xfs_log_recover.c index ad53e86..c66f9a1 100644 --- a/libxlog/xfs_log_recover.c +++ b/libxlog/xfs_log_recover.c @@ -19,9 +19,7 @@ #include <xfs/libxlog.h> #define xfs_readonly_buftarg(buftarg) (0) - -/* avoid set-but-unused var warning. gcc is not very bright. */ -#define xlog_clear_stale_blocks(log, taillsn) ((taillsn) = (taillsn)) +#define xlog_clear_stale_blocks(log, taillsn) (0) /* diff --git a/logprint/logprint.c b/logprint/logprint.c index 5452e87..cf24b6e 100644 --- a/logprint/logprint.c +++ b/logprint/logprint.c @@ -93,6 +93,7 @@ logstat(xfs_mount_t *mp) x.logBBsize = XFS_FSB_TO_BB(mp, sb->sb_logblocks); x.logBBstart = XFS_FSB_TO_DADDR(mp, sb->sb_logstart); + x.lbsize = 1 << mp->m_sb.sb_logsectlog; if (!x.logname && sb->sb_logstart == 0) { fprintf(stderr, _(" external log device not specified\n\n")); usage(); @@ -104,6 +105,7 @@ logstat(xfs_mount_t *mp) stat(x.dname, &s); x.logBBsize = s.st_size >> 9; x.logBBstart = 0; + x.lbsize = 1; } @@ -235,6 +237,7 @@ main(int argc, char **argv) log.l_logsize = BBTOB(x.logBBsize); log.l_logBBstart = x.logBBstart; log.l_logBBsize = x.logBBsize; + log.l_sectBBsize = x.lbsize; log.l_mp = &mount; switch (print_operation) { diff --git a/repair/agheader.c b/repair/agheader.c index 769022d..bc8b1bf 100644 --- a/repair/agheader.c +++ b/repair/agheader.c @@ -22,6 +22,11 @@ #include "protos.h" #include "err_protos.h" +/* + * XXX (dgc): WTF is the point of all the check and repair here when phase 5 + * recreates the AGF/AGI/AGFL completely from scratch? + */ + static int verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i) { @@ -104,7 +109,20 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i) /* don't check freespace btrees -- will be checked by caller */ - return(retval); + if (!xfs_sb_version_hascrc(&mp->m_sb)) + return retval; + + if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) { + char uu[64]; + + retval = XR_AG_AGF; + platform_uuid_unparse(&agf->agf_uuid, uu); + do_warn(_("bad uuid %s for agf %d\n"), uu, i); + + if (!no_modify) + platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid); + } + return retval; } static int @@ -169,7 +187,21 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno) /* don't check inode btree -- will be checked by caller */ - return(retval); + if (!xfs_sb_version_hascrc(&mp->m_sb)) + return retval; + + if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) { + char uu[64]; + + retval = XR_AG_AGI; + platform_uuid_unparse(&agi->agi_uuid, uu); + do_warn(_("bad uuid %s for agi %d\n"), uu, agno); + + if (!no_modify) + platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid); + } + + return retval; } /* diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 3e7e225..280423b 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -629,7 +629,7 @@ process_inode_chunk( bplist[bp_index] = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, blks_per_cluster), 0, - NULL); + &xfs_inode_buf_ops); if (!bplist[bp_index]) { do_warn(_("cannot read inode %" PRIu64 ", disk block %" PRId64 ", cnt %d\n"), XFS_AGINO_TO_INO(mp, agno, first_irec->ino_startnum), @@ -776,8 +776,11 @@ process_inode_chunk( extra_attr_check, &isa_dir, &parent); ASSERT(is_used != 3); - if (ino_dirty) + if (ino_dirty) { dirty = 1; + libxfs_dinode_calc_crc(mp, dino); + } + /* * XXX - if we want to try and keep * track of whether we need to bang on diff --git a/repair/dinode.c b/repair/dinode.c index 7a75dc8..5e1633b 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -86,139 +86,127 @@ _("would have cleared inode %" PRIu64 " attributes\n"), ino_num); } static int -clear_dinode_core(xfs_dinode_t *dinoc, xfs_ino_t ino_num) +clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num) { int dirty = 0; + int i; - if (be16_to_cpu(dinoc->di_magic) != XFS_DINODE_MAGIC) { - dirty = 1; - - if (no_modify) - return(1); +#define __dirty_no_modify_ret(dirty) \ + ({ (dirty) = 1; if (no_modify) return 1; }) + if (be16_to_cpu(dinoc->di_magic) != XFS_DINODE_MAGIC) { + __dirty_no_modify_ret(dirty); dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); } if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) || (!fs_inode_nlink && dinoc->di_version > 1)) { - dirty = 1; - - if (no_modify) - return(1); - - dinoc->di_version = (fs_inode_nlink) ? 2 : 1; + __dirty_no_modify_ret(dirty); + if (xfs_sb_version_hascrc(&mp->m_sb)) + dinoc->di_version = 3; + else + dinoc->di_version = (fs_inode_nlink) ? 2 : 1; } if (be16_to_cpu(dinoc->di_mode) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_mode = 0; } if (be16_to_cpu(dinoc->di_flags) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_flags = 0; } if (be32_to_cpu(dinoc->di_dmevmask) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_dmevmask = 0; } if (dinoc->di_forkoff != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_forkoff = 0; } if (dinoc->di_format != XFS_DINODE_FMT_EXTENTS) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_format = XFS_DINODE_FMT_EXTENTS; } if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS; } if (be64_to_cpu(dinoc->di_size) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_size = 0; } if (be64_to_cpu(dinoc->di_nblocks) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_nblocks = 0; } if (be16_to_cpu(dinoc->di_onlink) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_onlink = 0; } if (be32_to_cpu(dinoc->di_nextents) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_nextents = 0; } if (be16_to_cpu(dinoc->di_anextents) != 0) { - dirty = 1; - - if (no_modify) - return(1); - + __dirty_no_modify_ret(dirty); dinoc->di_anextents = 0; } if (dinoc->di_version > 1 && be32_to_cpu(dinoc->di_nlink) != 0) { - dirty = 1; + __dirty_no_modify_ret(dirty); + dinoc->di_nlink = 0; + } - if (no_modify) - return(1); + /* we are done for version 1/2 inodes */ + if (dinoc->di_version < 3) + return dirty; - dinoc->di_nlink = 0; + if (be64_to_cpu(dinoc->di_ino) != ino_num) { + __dirty_no_modify_ret(dirty); + dinoc->di_ino = cpu_to_be64(ino_num); } - return(dirty); + if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) { + __dirty_no_modify_ret(dirty); + platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid); + } + + for (i = 0; i < 16; i++) { + if (dinoc->di_pad[i] != 0) { + __dirty_no_modify_ret(dirty); + memset(dinoc->di_pad, 0, 16); + break; + } + } + + if (be64_to_cpu(dinoc->di_flags2) != 0) { + __dirty_no_modify_ret(dirty); + dinoc->di_flags2 = 0; + } + + if (be64_to_cpu(dinoc->di_lsn) != 0) { + __dirty_no_modify_ret(dirty); + dinoc->di_lsn = 0; + } + + if (be64_to_cpu(dinoc->di_changecount) != 0) { + __dirty_no_modify_ret(dirty); + dinoc->di_changecount = 0; + } + + return dirty; } static int @@ -244,7 +232,7 @@ clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num) { int dirty; - dirty = clear_dinode_core(dino, ino_num); + dirty = clear_dinode_core(mp, dino, ino_num); dirty += clear_dinode_unlinked(mp, dino); /* and clear the forks */ @@ -1127,6 +1115,7 @@ process_btinode( int level; int numrecs; bmap_cursor_t cursor; + __uint64_t magic; dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); lino = XFS_AGINO_TO_INO(mp, agno, ino); @@ -1138,6 +1127,9 @@ process_btinode( else forkname = _("attr"); + magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_BMAP_CRC_MAGIC + : XFS_BMAP_MAGIC; + level = be16_to_cpu(dib->bb_level); numrecs = be16_to_cpu(dib->bb_numrecs); @@ -1191,9 +1183,9 @@ _("bad numrecs 0 in inode %" PRIu64 " bmap btree root block\n"), return(1); } - if (scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, + if (scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt, type, whichfork, lino, tot, nex, blkmapp, &cursor, - 1, check_dups)) + 1, check_dups, magic, &xfs_bmbt_buf_ops)) return(1); /* * fix key (offset) mismatches between the keys in root @@ -1512,9 +1504,21 @@ _("cannot read inode %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), return(1); } + buf_data = (char *)XFS_BUF_PTR(bp); - size = MIN(be64_to_cpu(dino->di_size) - amountdone, - XFS_FSB_TO_BB(mp, 1) * BBSIZE); + size = MIN(be64_to_cpu(dino->di_size) - amountdone, + XFS_SYMLINK_BUF_SPACE(mp, + mp->m_sb.sb_blocksize)); + if (xfs_sb_version_hascrc(&mp->m_sb)) { + if (!libxfs_symlink_hdr_ok(mp, lino, amountdone, + size, bp)) { + do_warn( +_("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"), + lino, i, fsbno); + return(1); + } + buf_data += sizeof(struct xfs_dsymlink_hdr); + } memmove(cptr, buf_data, size); cptr += size; amountdone += size; @@ -2464,7 +2468,8 @@ process_dinode_int(xfs_mount_t *mp, } if (!XFS_DINODE_GOOD_VERSION(dino->di_version) || - (!fs_inode_nlink && dino->di_version > 1)) { + (!fs_inode_nlink && dino->di_version > 1) || + (xfs_sb_version_hascrc(&mp->m_sb) && dino->di_version < 3) ) { retval = 1; if (!uncertain) do_warn(_("bad version number 0x%x on inode %" PRIu64 "%c"), @@ -2473,7 +2478,9 @@ process_dinode_int(xfs_mount_t *mp, if (!verify_mode) { if (!no_modify) { do_warn(_(" resetting version number\n")); - dino->di_version = (fs_inode_nlink) ? 2 : 1; + dino->di_version = + xfs_sb_version_hascrc(&mp->m_sb) ? 3 : + (fs_inode_nlink) ? 2 : 1; *dirty = 1; } else do_warn(_(" would reset version number\n")); @@ -2481,6 +2488,31 @@ process_dinode_int(xfs_mount_t *mp, } /* + * We don't bother checking the CRC here - we cannot guarantee that when + * we are called here that the inode has not already been modified in + * memory and hence invalidated the CRC. + */ + if (xfs_sb_version_hascrc(&mp->m_sb)) { + if (be64_to_cpu(dino->di_ino) != lino) { + if (!uncertain) + do_warn( +_("inode identifier %" PRIu64 " mismatch on inode %" PRIu64 "\n"), + be64_to_cpu(dino->di_ino), lino); + if (verify_mode) + return 1; + goto clear_bad_out; + } + if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) { + if (!uncertain) + do_warn( + _("UUID mismatch on inode %" PRIu64 "\n"), lino); + if (verify_mode) + return 1; + goto clear_bad_out; + } + } + + /* * blow out of here if the inode size is < 0 */ if ((xfs_fsize_t)be64_to_cpu(dino->di_size) < 0) { diff --git a/repair/phase2.c b/repair/phase2.c index 5a4cf10..0481f51 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -64,6 +64,7 @@ zero_log(xfs_mount_t *mp) ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); } log.l_sectbb_mask = (1 << log.l_sectbb_log) - 1; + log.l_sectBBsize = 1 << mp->m_sb.sb_logsectlog; if ((error = xlog_find_tail(&log, &head_blk, &tail_blk))) { do_warn(_("zero_log: cannot find log head/tail " diff --git a/repair/phase5.c b/repair/phase5.c index 7d5cd49..52d035f 100644 --- a/repair/phase5.c +++ b/repair/phase5.c @@ -602,6 +602,12 @@ prop_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_alloc_ptr_t *bt_ptr; xfs_agblock_t agbno; bt_stat_level_t *lptr; + __uint32_t crc_magic; + + if (magic == XFS_ABTB_MAGIC) + crc_magic = XFS_ABTB_CRC_MAGIC; + else + crc_magic = XFS_ABTC_CRC_MAGIC; level++; @@ -650,14 +656,17 @@ prop_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, /* * initialize block header */ + lptr->buf_p->b_ops = &xfs_allocbt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, lptr->buf_p, crc_magic, level, + 0, agno, XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, lptr->buf_p, magic, level, + 0, agno, 0); - bt_hdr->bb_magic = cpu_to_be32(magic); - bt_hdr->bb_level = cpu_to_be16(level); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); - bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); - bt_hdr->bb_numrecs = 0; /* * propagate extent record for first extent in new block up @@ -699,6 +708,7 @@ build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, extent_tree_node_t *ext_ptr; bt_stat_level_t *lptr; xfs_extlen_t freeblks; + __uint32_t crc_magic; #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "in build_freespace_tree, agno = %d\n", agno); @@ -707,6 +717,10 @@ build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, freeblks = 0; ASSERT(level > 0); + if (magic == XFS_ABTB_MAGIC) + crc_magic = XFS_ABTB_CRC_MAGIC; + else + crc_magic = XFS_ABTC_CRC_MAGIC; /* * initialize the first block on each btree level @@ -728,14 +742,15 @@ build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, /* * initialize block header */ + lptr->buf_p->b_ops = &xfs_allocbt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); - - bt_hdr->bb_magic = cpu_to_be32(magic); - bt_hdr->bb_level = cpu_to_be16(i); - bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); - bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); - bt_hdr->bb_numrecs = 0; + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, lptr->buf_p, crc_magic, i, + 0, agno, XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, lptr->buf_p, magic, i, + 0, agno, 0); } /* * run along leaf, setting up records. as we have to switch @@ -759,13 +774,17 @@ build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, /* * block initialization, lay in block header */ + lptr->buf_p->b_ops = &xfs_allocbt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, lptr->buf_p, crc_magic, 0, + 0, agno, XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, lptr->buf_p, magic, 0, + 0, agno, 0); - bt_hdr->bb_magic = cpu_to_be32(magic); - bt_hdr->bb_level = 0; bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); - bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb + (lptr->modulo > 0)); #ifdef XR_BLD_FREE_TRACE @@ -996,14 +1015,19 @@ prop_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, /* * initialize block header */ + lptr->buf_p->b_ops = &xfs_inobt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_CRC_MAGIC, + level, 0, agno, + XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC, + level, 0, agno, 0); - bt_hdr->bb_magic = cpu_to_be32(XFS_IBT_MAGIC); - bt_hdr->bb_level = cpu_to_be16(level); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); - bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); - bt_hdr->bb_numrecs = 0; + /* * propagate extent record for first extent in new block up */ @@ -1024,6 +1048,9 @@ prop_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); } +/* + * XXX: yet more code that can be shared with mkfs, growfs. + */ static void build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_agino_t first_agino, @@ -1036,6 +1063,7 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, agi_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); + agi_buf->b_ops = &xfs_agi_buf_ops; agi = XFS_BUF_TO_AGI(agi_buf); memset(agi, 0, mp->m_sb.sb_sectsize); @@ -1057,6 +1085,9 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO); + if (xfs_sb_version_hascrc(&mp->m_sb)) + platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid); + libxfs_writebuf(agi_buf, 0); } @@ -1099,15 +1130,19 @@ build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, /* * initialize block header */ + + lptr->buf_p->b_ops = &xfs_inobt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); - - bt_hdr->bb_magic = cpu_to_be32(XFS_IBT_MAGIC); - bt_hdr->bb_level = cpu_to_be16(i); - bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); - bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); - bt_hdr->bb_numrecs = 0; + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_CRC_MAGIC, + i, 0, agno, + XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC, + i, 0, agno, 0); } + /* * run along leaf, setting up records. as we have to switch * blocks, call the prop_ino_cursor routine to set up the new @@ -1127,13 +1162,18 @@ build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, /* * block initialization, lay in block header */ + lptr->buf_p->b_ops = &xfs_inobt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_CRC_MAGIC, + 0, 0, agno, + XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC, + 0, 0, agno, 0); - bt_hdr->bb_magic = cpu_to_be32(XFS_IBT_MAGIC); - bt_hdr->bb_level = 0; bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); - bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb + (lptr->modulo > 0)); @@ -1192,7 +1232,9 @@ build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, /* * build both the agf and the agfl for an agno given both - * btree cursors + * btree cursors. + * + * XXX: yet more common code that can be shared with mkfs/growfs. */ static void build_agf_agfl(xfs_mount_t *mp, @@ -1208,10 +1250,12 @@ build_agf_agfl(xfs_mount_t *mp, int j; xfs_agfl_t *agfl; xfs_agf_t *agf; + __be32 *freelist; agf_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); + agf_buf->b_ops = &xfs_agf_buf_ops; agf = XFS_BUF_TO_AGF(agf_buf); memset(agf, 0, mp->m_sb.sb_sectsize); @@ -1265,31 +1309,45 @@ build_agf_agfl(xfs_mount_t *mp, XFS_BTNUM_CNT); #endif + if (xfs_sb_version_hascrc(&mp->m_sb)) + platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid); + + /* initialise the AGFL, then fill it if there are blocks left over. */ + agfl_buf = libxfs_getbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), + mp->m_sb.sb_sectsize/BBSIZE); + agfl_buf->b_ops = &xfs_agfl_buf_ops; + agfl = XFS_BUF_TO_AGFL(agfl_buf); + + /* setting to 0xff results in initialisation to NULLAGBLOCK */ + memset(agfl, 0xff, mp->m_sb.sb_sectsize); + if (xfs_sb_version_hascrc(&mp->m_sb)) { + agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); + agfl->agfl_seqno = cpu_to_be32(agno); + platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid); + for (i = 0; i < XFS_AGFL_SIZE(mp); i++) + agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK); + } + freelist = XFS_BUF_TO_AGFL_BNO(mp, agfl_buf); + /* * do we have left-over blocks in the btree cursors that should * be used to fill the AGFL? */ if (bno_bt->num_free_blocks > 0 || bcnt_bt->num_free_blocks > 0) { + /* - * yes - grab the AGFL buffer - */ - agfl_buf = libxfs_getbuf(mp->m_dev, - XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), - mp->m_sb.sb_sectsize/BBSIZE); - agfl = XFS_BUF_TO_AGFL(agfl_buf); - memset(agfl, 0, mp->m_sb.sb_sectsize); - /* - * ok, now grab as many blocks as we can + * yes, now grab as many blocks as we can */ i = j = 0; while (bno_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE(mp)) { - agfl->agfl_bno[i] = cpu_to_be32( + freelist[i] = cpu_to_be32( get_next_blockaddr(agno, 0, bno_bt)); i++; } while (bcnt_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE(mp)) { - agfl->agfl_bno[i] = cpu_to_be32( + freelist[i] = cpu_to_be32( get_next_blockaddr(agno, 0, bcnt_bt)); i++; } @@ -1324,13 +1382,14 @@ build_agf_agfl(xfs_mount_t *mp, fprintf(stderr, "writing agfl for ag %u\n", agno); #endif - libxfs_writebuf(agfl_buf, 0); } else { agf->agf_flfirst = 0; agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1); agf->agf_flcount = 0; } + libxfs_writebuf(agfl_buf, 0); + ext_ptr = findbiggest_bcnt_extent(agno); agf->agf_longest = cpu_to_be32((ext_ptr != NULL) ? ext_ptr->ex_blockcount : 0); @@ -1340,6 +1399,26 @@ build_agf_agfl(xfs_mount_t *mp, libxfs_writebuf(agf_buf, 0); + /* + * now fix up the free list appropriately + * XXX: code lifted from mkfs, shoul dbe shared. + */ + { + xfs_alloc_arg_t args; + xfs_trans_t *tp; + + memset(&args, 0, sizeof(args)); + args.tp = tp = libxfs_trans_alloc(mp, 0); + args.mp = mp; + args.agno = agno; + args.alignment = 1; + args.pag = xfs_perag_get(mp,agno); + libxfs_trans_reserve(tp, XFS_MIN_FREELIST(agf, mp), 0, 0, 0, 0); + libxfs_alloc_fix_freelist(&args, 0); + xfs_perag_put(args.pag); + libxfs_trans_commit(tp, 0); + } + #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "wrote agf for ag %u, error = %d\n", agno, error); #endif diff --git a/repair/prefetch.c b/repair/prefetch.c index ebe00c2..f5f8985 100644 --- a/repair/prefetch.c +++ b/repair/prefetch.c @@ -222,7 +222,7 @@ pf_scan_lbtree( int rc; bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dbno), - XFS_FSB_TO_BB(mp, 1), 0, NULL); + XFS_FSB_TO_BB(mp, 1), 0, &xfs_bmbt_buf_ops); if (!bp) return 0; @@ -338,6 +338,11 @@ pf_read_inode_dirs( int hasdir = 0; int isadir; + bp->b_ops = &xfs_inode_buf_ops; + bp->b_ops->verify_read(bp); + if (bp->b_error) + return; + for (icnt = 0; icnt < (XFS_BUF_COUNT(bp) >> mp->m_sb.sb_inodelog); icnt++) { dino = xfs_make_iptr(mp, bp, icnt); diff --git a/repair/scan.c b/repair/scan.c index 9f0ddaf..219b617 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -48,17 +48,6 @@ struct aghdr_cnts { __uint64_t ifreecount; }; -static void -scanfunc_allocbt( - struct xfs_btree_block *block, - int level, - xfs_agblock_t bno, - xfs_agnumber_t agno, - int suspect, - int isroot, - __uint32_t magic, - struct aghdr_cnts *agcnts); - void set_mp(xfs_mount_t *mpp) { @@ -78,20 +67,23 @@ scan_sbtree( xfs_agnumber_t agno, int suspect, int isroot, + __uint32_t magic, void *priv), int isroot, - void *priv) + __uint32_t magic, + void *priv, + const struct xfs_buf_ops *ops) { xfs_buf_t *bp; bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, root), - XFS_FSB_TO_BB(mp, 1), 0, NULL); + XFS_FSB_TO_BB(mp, 1), 0, ops); if (!bp) { do_error(_("can't read btree block %d/%d\n"), agno, root); return; } (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, root, agno, suspect, - isroot, priv); + isroot, magic, priv); libxfs_putbuf(bp); } @@ -114,7 +106,8 @@ scan_lbtree( bmap_cursor_t *bm_cursor, int isroot, int check_dups, - int *dirty), + int *dirty, + __uint64_t magic), int type, int whichfork, xfs_ino_t ino, @@ -123,14 +116,16 @@ scan_lbtree( blkmap_t **blkmapp, bmap_cursor_t *bm_cursor, int isroot, - int check_dups) + int check_dups, + __uint64_t magic, + const struct xfs_buf_ops *ops) { xfs_buf_t *bp; int err; int dirty = 0; bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, root), - XFS_FSB_TO_BB(mp, 1), 0, NULL); + XFS_FSB_TO_BB(mp, 1), 0, ops); if (!bp) { do_error(_("can't read btree block %d/%d\n"), XFS_FSB_TO_AGNO(mp, root), @@ -139,7 +134,8 @@ scan_lbtree( } err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, type, whichfork, root, ino, tot, nex, blkmapp, - bm_cursor, isroot, check_dups, &dirty); + bm_cursor, isroot, check_dups, &dirty, + magic); ASSERT(dirty == 0 || (dirty && !no_modify)); @@ -152,7 +148,7 @@ scan_lbtree( } int -scanfunc_bmap( +scan_bmapbt( struct xfs_btree_block *block, int level, int type, @@ -165,7 +161,8 @@ scanfunc_bmap( bmap_cursor_t *bm_cursor, int isroot, int check_dups, - int *dirty) + int *dirty, + __uint64_t magic) { int i; int err; @@ -192,7 +189,7 @@ scanfunc_bmap( * another inode are claiming the same block but that's * highly unlikely. */ - if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC) { + if (be32_to_cpu(block->bb_magic) != magic) { do_warn( _("bad magic # %#x in inode %" PRIu64 " (%s fork) bmbt block %" PRIu64 "\n"), be32_to_cpu(block->bb_magic), ino, forkname, bno); @@ -206,6 +203,16 @@ _("expected level %d got %d in inode %" PRIu64 ", (%s fork) bmbt block %" PRIu64 return(1); } + if (magic == XFS_BMAP_CRC_MAGIC) { + /* verify owner */ + if (be64_to_cpu(block->bb_u.l.bb_owner) != ino) { + do_warn( +_("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), + ino, be64_to_cpu(block->bb_u.l.bb_owner), bno); + return(1); + } + } + if (check_dups == 0) { /* * check sibling pointers. if bad we have a conflict @@ -408,9 +415,10 @@ _("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"), return(1); } - err = scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, + err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt, type, whichfork, ino, tot, nex, blkmapp, - bm_cursor, 0, check_dups); + bm_cursor, 0, check_dups, magic, + &xfs_bmbt_buf_ops); if (err) return(1); @@ -481,35 +489,7 @@ _("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLDFSBNO)\n" } static void -scanfunc_bno( - struct xfs_btree_block *block, - int level, - xfs_agblock_t bno, - xfs_agnumber_t agno, - int suspect, - int isroot, - void *agcnts) -{ - return scanfunc_allocbt(block, level, bno, agno, - suspect, isroot, XFS_ABTB_MAGIC, agcnts); -} - -static void -scanfunc_cnt( - struct xfs_btree_block *block, - int level, - xfs_agblock_t bno, - xfs_agnumber_t agno, - int suspect, - int isroot, - void *agcnts) -{ - return scanfunc_allocbt(block, level, bno, agno, - suspect, isroot, XFS_ABTC_MAGIC, agcnts); -} - -static void -scanfunc_allocbt( +scan_allocbt( struct xfs_btree_block *block, int level, xfs_agblock_t bno, @@ -517,8 +497,9 @@ scanfunc_allocbt( int suspect, int isroot, __uint32_t magic, - struct aghdr_cnts *agcnts) + void *priv) { + struct aghdr_cnts *agcnts = priv; const char *name; int i; xfs_alloc_ptr_t *pp; @@ -529,9 +510,19 @@ scanfunc_allocbt( xfs_extlen_t lastcount = 0; xfs_agblock_t lastblock = 0; - assert(magic == XFS_ABTB_MAGIC || magic == XFS_ABTC_MAGIC); - - name = (magic == XFS_ABTB_MAGIC) ? "bno" : "cnt"; + switch (magic) { + case XFS_ABTB_CRC_MAGIC: + case XFS_ABTB_MAGIC: + name = "bno"; + break; + case XFS_ABTC_CRC_MAGIC: + case XFS_ABTC_MAGIC: + name = "cnt"; + break; + default: + assert(0); + break; + } if (be32_to_cpu(block->bb_magic) != magic) { do_warn(_("bad magic # %#x in bt%s block %d/%d\n"), @@ -615,7 +606,8 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), continue; } - if (magic == XFS_ABTB_MAGIC) { + if (magic == XFS_ABTB_MAGIC || + magic == XFS_ABTB_CRC_MAGIC) { if (b <= lastblock) { do_warn(_( "out-of-order bno btree record %d (%u %u) block %u/%u\n"), @@ -648,7 +640,8 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), * no warning messages -- we'll catch * FREE1 blocks later */ - if (magic == XFS_ABTC_MAGIC) { + if (magic == XFS_ABTC_MAGIC || + magic == XFS_ABTC_CRC_MAGIC) { set_bmap_ext(agno, b, blen, XR_E_FREE); break; @@ -709,10 +702,20 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), * as possible. */ if (bno != 0 && verify_agbno(mp, agno, bno)) { - scan_sbtree(bno, level, agno, suspect, - (magic == XFS_ABTB_MAGIC) ? - scanfunc_bno : scanfunc_cnt, 0, - (void *)agcnts); + switch (magic) { + case XFS_ABTB_CRC_MAGIC: + case XFS_ABTB_MAGIC: + scan_sbtree(bno, level, agno, suspect, + scan_allocbt, 0, magic, priv, + &xfs_allocbt_buf_ops); + break; + case XFS_ABTC_CRC_MAGIC: + case XFS_ABTC_MAGIC: + scan_sbtree(bno, level, agno, suspect, + scan_allocbt, 0, magic, priv, + &xfs_allocbt_buf_ops); + break; + } } } } @@ -896,13 +899,14 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n") * that we aren't sure about go into the uncertain list. */ static void -scanfunc_ino( +scan_inobt( struct xfs_btree_block *block, int level, xfs_agblock_t bno, xfs_agnumber_t agno, int suspect, int isroot, + __uint32_t magic, void *priv) { struct aghdr_cnts *agcnts = priv; @@ -915,7 +919,7 @@ scanfunc_ino( hdr_errors = 0; - if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC) { + if (be32_to_cpu(block->bb_magic) != magic) { do_warn(_("bad magic # %#x in inobt block %d/%d\n"), be32_to_cpu(block->bb_magic), agno, bno); hdr_errors++; @@ -1032,7 +1036,8 @@ _("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), if (be32_to_cpu(pp[i]) != 0 && verify_agbno(mp, agno, be32_to_cpu(pp[i]))) scan_sbtree(be32_to_cpu(pp[i]), level, agno, - suspect, scanfunc_ino, 0, priv); + suspect, scan_inobt, 0, magic, priv, + &xfs_inobt_buf_ops); } } @@ -1041,12 +1046,12 @@ scan_freelist( xfs_agf_t *agf, struct aghdr_cnts *agcnts) { - xfs_agfl_t *agfl; xfs_buf_t *agflbuf; xfs_agnumber_t agno; xfs_agblock_t bno; int count; int i; + __be32 *freelist; agno = be32_to_cpu(agf->agf_seqno); @@ -1065,11 +1070,11 @@ scan_freelist( do_abort(_("can't read agfl block for ag %d\n"), agno); return; } - agfl = XFS_BUF_TO_AGFL(agflbuf); + freelist = XFS_BUF_TO_AGFL_BNO(mp, agflbuf); i = be32_to_cpu(agf->agf_flfirst); count = 0; for (;;) { - bno = be32_to_cpu(agfl->agfl_bno[i]); + bno = be32_to_cpu(freelist[i]); if (verify_agbno(mp, agno, bno)) set_bmap(agno, bno, XR_E_FREE); else @@ -1098,11 +1103,15 @@ validate_agf( struct aghdr_cnts *agcnts) { xfs_agblock_t bno; + __uint32_t magic; bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]); if (bno != 0 && verify_agbno(mp, agno, bno)) { + magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC + : XFS_ABTB_MAGIC; scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]), - agno, 0, scanfunc_bno, 1, agcnts); + agno, 0, scan_allocbt, 1, magic, agcnts, + &xfs_allocbt_buf_ops); } else { do_warn(_("bad agbno %u for btbno root, agno %d\n"), bno, agno); @@ -1110,8 +1119,11 @@ validate_agf( bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]); if (bno != 0 && verify_agbno(mp, agno, bno)) { + magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTC_CRC_MAGIC + : XFS_ABTC_MAGIC; scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]), - agno, 0, scanfunc_cnt, 1, agcnts); + agno, 0, scan_allocbt, 1, magic, agcnts, + &xfs_allocbt_buf_ops); } else { do_warn(_("bad agbno %u for btbcnt root, agno %d\n"), bno, agno); @@ -1142,11 +1154,15 @@ validate_agi( { xfs_agblock_t bno; int i; + __uint32_t magic; bno = be32_to_cpu(agi->agi_root); if (bno != 0 && verify_agbno(mp, agno, bno)) { + magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC + : XFS_IBT_MAGIC; scan_sbtree(bno, be32_to_cpu(agi->agi_level), - agno, 0, scanfunc_ino, 1, agcnts); + agno, 0, scan_inobt, 1, magic, agcnts, + &xfs_inobt_buf_ops); } else { do_warn(_("bad agbno %u for inobt root, agno %d\n"), be32_to_cpu(agi->agi_root), agno); diff --git a/repair/scan.h b/repair/scan.h index 9f945cf..92593e9 100644 --- a/repair/scan.h +++ b/repair/scan.h @@ -35,7 +35,8 @@ int scan_lbtree( bmap_cursor_t *bm_cursor, int isroot, int check_dups, - int *dirty), + int *dirty, + __uint64_t magic), int type, int whichfork, xfs_ino_t ino, @@ -44,9 +45,11 @@ int scan_lbtree( struct blkmap **blkmapp, bmap_cursor_t *bm_cursor, int isroot, - int check_dups); + int check_dups, + __uint64_t magic, + const struct xfs_buf_ops *ops); -int scanfunc_bmap( +int scan_bmapbt( struct xfs_btree_block *block, int level, int type, @@ -59,7 +62,8 @@ int scanfunc_bmap( bmap_cursor_t *bm_cursor, int isroot, int check_dups, - int *dirty); + int *dirty, + __uint64_t magic); void scan_ags( diff --git a/repair/versions.c b/repair/versions.c index 957766a..c11a728 100644 --- a/repair/versions.c +++ b/repair/versions.c @@ -165,7 +165,7 @@ _("This filesystem contains features not understood by this program.\n")); return(1); } - if (XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_4) { + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_4) { if (!fs_sb_feature_bits_allowed) { if (!no_modify) { do_warn( diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index 167b1f6..8eefc48 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -612,7 +612,7 @@ main(int argc, char **argv) glob_agcount = mp->m_sb.sb_agcount; chunks_pblock = mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK; - max_symlink_blocks = howmany(MAXPATHLEN - 1, mp->m_sb.sb_blocksize); + max_symlink_blocks = libxfs_symlink_blocks(mp, MAXPATHLEN); inodes_per_cluster = MAX(mp->m_sb.sb_inopblock, XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); -- 1.7.10 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs