xfs
[Top] [All Lists]

[PATCH 24/48] xfsprogs: add crc format support to repair

To: xfs@xxxxxxxxxxx
Subject: [PATCH 24/48] xfsprogs: add crc format support to repair
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Fri, 7 Jun 2013 10:25:47 +1000
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1370564771-4929-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1370564771-4929-1-git-send-email-david@xxxxxxxxxxxxx>
From: Dave Chinner <dchinner@xxxxxxxxxx>

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 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              |   19 ++++-
 libxfs/xfs.h               |   12 ++-
 libxfs/xfs_alloc.c         |    7 +-
 libxfs/xfs_btree.c         |   20 +++--
 repair/agheader.c          |   36 ++++++++-
 repair/dino_chunks.c       |    7 +-
 repair/dinode.c            |  190 ++++++++++++++++++++++++++------------------
 repair/phase2.c            |    1 +
 repair/phase5.c            |  152 ++++++++++++++++++++++++++---------
 repair/prefetch.c          |    7 +-
 repair/scan.c              |  152 +++++++++++++++++++----------------
 repair/scan.h              |   12 ++-
 repair/versions.c          |    2 +-
 repair/xfs_repair.c        |    2 +-
 20 files changed, 422 insertions(+), 215 deletions(-)

diff --git a/include/libxfs.h b/include/libxfs.h
index d5131c1..4bb4ad4 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -682,6 +682,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
 
@@ -690,6 +691,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 70c3ea0..e160339 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 8a28b89..20d66b0 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 a1bfa7a..7f5ae6b 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 f91a5d0..c679f81 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -445,6 +445,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;
 }
@@ -833,10 +834,20 @@ libxfs_writebufr(xfs_buf_t *bp)
                }
        }
 
+       /*
+        * 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 bp->b_error;
+               }
        }
 
        if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) {
@@ -883,6 +894,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 9246f36..aa71ecc 100644
--- a/libxfs/xfs.h
+++ b/libxfs/xfs.h
@@ -69,8 +69,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 1041f8f..1d7ea8f 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 a613294..b11131c 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/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 21078d0..d3c2236 100644
--- a/repair/dino_chunks.c
+++ b/repair/dino_chunks.c
@@ -628,7 +628,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),
@@ -775,8 +775,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 66eedc2..2df9a91 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -85,139 +85,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
@@ -243,7 +231,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 */
@@ -1126,6 +1114,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);
@@ -1137,6 +1126,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);
 
@@ -1190,9 +1182,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
@@ -1520,9 +1512,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;
@@ -2484,7 +2488,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"),
@@ -2493,7 +2498,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"));
@@ -2501,6 +2508,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 %llu 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 2817fed..a62854e 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 c7cef4f..2eae42a 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,
@@ -1213,6 +1255,7 @@ build_agf_agfl(xfs_mount_t        *mp,
        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);
 
@@ -1266,22 +1309,34 @@ 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);
-               freelist = XFS_BUF_TO_AGFL_BNO(mp, 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))  {
@@ -1326,13 +1381,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);
@@ -1342,6 +1398,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 93b4146..7529f5d 100644
--- a/repair/prefetch.c
+++ b/repair/prefetch.c
@@ -221,7 +221,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;
 
@@ -337,6 +337,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 0b5ab1b..d58d55a 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);
        }
 }
 
@@ -1109,11 +1114,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);
@@ -1121,8 +1130,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);
@@ -1153,11 +1165,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 7623560..4708c5c 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -611,7 +611,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.4

<Prev in Thread] Current Thread [Next in Thread>