xfs
[Top] [All Lists]

[PATCH 03/48] libxfs: add crc format changes to generic btrees

To: xfs@xxxxxxxxxxx
Subject: [PATCH 03/48] libxfs: add crc format changes to generic btrees
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Fri, 7 Jun 2013 10:25:26 +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           |   15 +--
 include/xfs_alloc_btree.h  |   13 ++-
 include/xfs_bmap_btree.h   |   20 ++--
 include/xfs_btree.h        |   60 +++++++++--
 include/xfs_buf_item.h     |   24 ++++-
 include/xfs_dinode.h       |    4 +-
 include/xfs_ialloc_btree.h |   10 +-
 include/xfs_trans.h        |    2 +
 libxfs/rdwr.c              |   24 ++---
 libxfs/xfs.h               |    4 +
 libxfs/xfs_alloc_btree.c   |   99 +++++++++++------
 libxfs/xfs_attr_leaf.c     |    2 +-
 libxfs/xfs_bmap.c          |   49 ++++++---
 libxfs/xfs_bmap_btree.c    |  107 ++++++++++++------
 libxfs/xfs_btree.c         |  257 ++++++++++++++++++++++++++++++++++++--------
 libxfs/xfs_ialloc_btree.c  |   80 +++++++++-----
 libxfs/xfs_inode.c         |   33 +++---
 libxfs/xfs_mount.c         |    2 +-
 mdrestore/Makefile         |    2 +-
 19 files changed, 587 insertions(+), 220 deletions(-)

diff --git a/include/libxfs.h b/include/libxfs.h
index b6e83f4..a4564fd 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -240,14 +240,14 @@ struct xfs_buf_ops {
 typedef struct xfs_buf {
        struct cache_node       b_node;
        unsigned int            b_flags;
-       xfs_daddr_t             b_blkno;
+       xfs_daddr_t             b_bn;
        unsigned                b_bcount;
        unsigned int            b_length;
        dev_t                   b_dev;
        pthread_mutex_t         b_lock;
        pthread_t               b_holder;
        unsigned int            b_recur;
-       void                    *b_fsprivate;
+       void                    *b_fspriv;
        void                    *b_fsprivate2;
        void                    *b_fsprivate3;
        void                    *b_addr;
@@ -273,9 +273,11 @@ enum xfs_buf_flags_t {     /* b_flags bits */
        LIBXFS_B_DISCONTIG      = 0x0010,       /* discontiguous buffer */
 };
 
+#define XFS_BUF_DADDR_NULL             ((xfs_daddr_t) (-1LL))
+
 #define XFS_BUF_PTR(bp)                        ((char *)(bp)->b_addr)
 #define xfs_buf_offset(bp, offset)     (XFS_BUF_PTR(bp) + (offset))
-#define XFS_BUF_ADDR(bp)               ((bp)->b_blkno)
+#define XFS_BUF_ADDR(bp)               ((bp)->b_bn)
 #define XFS_BUF_SIZE(bp)               ((bp)->b_bcount)
 #define XFS_BUF_COUNT(bp)              ((bp)->b_bcount)
 #define XFS_BUF_TARGET(bp)             ((bp)->b_dev)
@@ -284,11 +286,11 @@ enum xfs_buf_flags_t {    /* b_flags bits */
        XFS_BUF_SET_COUNT(bp,cnt);              \
 })
 
-#define XFS_BUF_SET_ADDR(bp,blk)       ((bp)->b_blkno = (blk))
+#define XFS_BUF_SET_ADDR(bp,blk)       ((bp)->b_bn = (blk))
 #define XFS_BUF_SET_COUNT(bp,cnt)      ((bp)->b_bcount = (cnt))
 
-#define XFS_BUF_FSPRIVATE(bp,type)     ((type)(bp)->b_fsprivate)
-#define XFS_BUF_SET_FSPRIVATE(bp,val)  (bp)->b_fsprivate = (void *)(val)
+#define XFS_BUF_FSPRIVATE(bp,type)     ((type)(bp)->b_fspriv)
+#define XFS_BUF_SET_FSPRIVATE(bp,val)  (bp)->b_fspriv = (void *)(val)
 #define XFS_BUF_FSPRIVATE2(bp,type)    ((type)(bp)->b_fsprivate2)
 #define XFS_BUF_SET_FSPRIVATE2(bp,val) (bp)->b_fsprivate2 = (void *)(val)
 #define XFS_BUF_FSPRIVATE3(bp,type)    ((type)(bp)->b_fsprivate3)
@@ -392,6 +394,7 @@ typedef struct xfs_log_item {
        struct xfs_log_item_desc        *li_desc;       /* ptr to current desc*/
        struct xfs_mount                *li_mountp;     /* ptr to fs mount */
        uint                            li_type;        /* item type */
+       xfs_lsn_t                       li_lsn;
 } xfs_log_item_t;
 
 typedef struct xfs_inode_log_item {
diff --git a/include/xfs_alloc_btree.h b/include/xfs_alloc_btree.h
index 7e89a2b..70c3ea0 100644
--- a/include/xfs_alloc_btree.h
+++ b/include/xfs_alloc_btree.h
@@ -31,8 +31,10 @@ struct xfs_mount;
  * by blockcount and blockno.  All blocks look the same to make the code
  * simpler; if we have time later, we'll make the optimizations.
  */
-#define        XFS_ABTB_MAGIC  0x41425442      /* 'ABTB' for bno tree */
-#define        XFS_ABTC_MAGIC  0x41425443      /* 'ABTC' for cnt tree */
+#define        XFS_ABTB_MAGIC          0x41425442      /* 'ABTB' for bno tree 
*/
+#define        XFS_ABTB_CRC_MAGIC      0x41423342      /* 'AB3B' */
+#define        XFS_ABTC_MAGIC          0x41425443      /* 'ABTC' for cnt tree 
*/
+#define        XFS_ABTC_CRC_MAGIC      0x41423343      /* 'AB3C' */
 
 /*
  * Data record/key structure
@@ -59,10 +61,11 @@ typedef __be32 xfs_alloc_ptr_t;
 
 /*
  * Btree block header size depends on a superblock flag.
- *
- * (not quite yet, but soon)
  */
-#define XFS_ALLOC_BLOCK_LEN(mp)        XFS_BTREE_SBLOCK_LEN
+#define XFS_ALLOC_BLOCK_LEN(mp) \
+       (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
+        XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \
+        XFS_BTREE_SBLOCK_LEN)
 
 /*
  * Record, key, and pointer address macros for btree blocks.
diff --git a/include/xfs_bmap_btree.h b/include/xfs_bmap_btree.h
index 88469ca..8a28b89 100644
--- a/include/xfs_bmap_btree.h
+++ b/include/xfs_bmap_btree.h
@@ -18,7 +18,8 @@
 #ifndef __XFS_BMAP_BTREE_H__
 #define __XFS_BMAP_BTREE_H__
 
-#define XFS_BMAP_MAGIC 0x424d4150      /* 'BMAP' */
+#define XFS_BMAP_MAGIC         0x424d4150      /* 'BMAP' */
+#define XFS_BMAP_CRC_MAGIC     0x424d4133      /* 'BMA3' */
 
 struct xfs_btree_cur;
 struct xfs_btree_block;
@@ -136,10 +137,11 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
 
 /*
  * Btree block header size depends on a superblock flag.
- *
- * (not quite yet, but soon)
  */
-#define XFS_BMBT_BLOCK_LEN(mp) XFS_BTREE_LBLOCK_LEN
+#define XFS_BMBT_BLOCK_LEN(mp) \
+       (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
+        XFS_BTREE_LBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \
+        XFS_BTREE_LBLOCK_LEN)
 
 #define XFS_BMBT_REC_ADDR(mp, block, index) \
        ((xfs_bmbt_rec_t *) \
@@ -186,12 +188,12 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
 #define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \
        XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0))
 
-#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \
-       (int)(XFS_BTREE_LBLOCK_LEN + \
+#define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \
+       (int)(XFS_BMBT_BLOCK_LEN(mp) + \
               ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
 
-#define XFS_BMAP_BROOT_SPACE(bb) \
-       (XFS_BMAP_BROOT_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs)))
+#define XFS_BMAP_BROOT_SPACE(mp, bb) \
+       (XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs)))
 #define XFS_BMDR_SPACE_CALC(nrecs) \
        (int)(sizeof(xfs_bmdr_block_t) + \
               ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
@@ -204,7 +206,7 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
 /*
  * Prototypes for xfs_bmap.c to call.
  */
-extern void xfs_bmdr_to_bmbt(struct xfs_mount *, xfs_bmdr_block_t *, int,
+extern void xfs_bmdr_to_bmbt(struct xfs_inode *, xfs_bmdr_block_t *, int,
                        struct xfs_btree_block *, int);
 extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s);
 extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r);
diff --git a/include/xfs_btree.h b/include/xfs_btree.h
index be1eb23..02f89d8 100644
--- a/include/xfs_btree.h
+++ b/include/xfs_btree.h
@@ -42,11 +42,15 @@ extern kmem_zone_t  *xfs_btree_cur_zone;
  * Generic btree header.
  *
  * This is a combination of the actual format used on disk for short and long
- * format btrees.  The first three fields are shared by both format, but
- * the pointers are different and should be used with care.
+ * format btrees.  The first three fields are shared by both format, but the
+ * pointers are different and should be used with care.
  *
- * To get the size of the actual short or long form headers please use
- * the size macros below.  Never use sizeof(xfs_btree_block).
+ * To get the size of the actual short or long form headers please use the size
+ * macros below.  Never use sizeof(xfs_btree_block).
+ *
+ * The blkno, crc, lsn, owner and uuid fields are only available in filesystems
+ * with the crc feature bit, and all accesses to them must be conditional on
+ * that flag.
  */
 struct xfs_btree_block {
        __be32          bb_magic;       /* magic number for block type */
@@ -56,16 +60,35 @@ struct xfs_btree_block {
                struct {
                        __be32          bb_leftsib;
                        __be32          bb_rightsib;
+
+                       __be64          bb_blkno;
+                       __be64          bb_lsn;
+                       uuid_t          bb_uuid;
+                       __be32          bb_owner;
+                       __le32          bb_crc;
                } s;                    /* short form pointers */
                struct  {
                        __be64          bb_leftsib;
                        __be64          bb_rightsib;
+
+                       __be64          bb_blkno;
+                       __be64          bb_lsn;
+                       uuid_t          bb_uuid;
+                       __be64          bb_owner;
+                       __le32          bb_crc;
+                       __be32          bb_pad; /* padding for alignment */
                } l;                    /* long form pointers */
        } bb_u;                         /* rest */
 };
 
 #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 */
+
+#define XFS_BTREE_SBLOCK_CRC_OFF \
+       offsetof(struct xfs_btree_block, bb_u.s.bb_crc)
+#define XFS_BTREE_LBLOCK_CRC_OFF \
+       offsetof(struct xfs_btree_block, bb_u.l.bb_crc)
 
 
 /*
@@ -101,13 +124,11 @@ union xfs_btree_rec {
 #define        XFS_BB_NUMRECS          0x04
 #define        XFS_BB_LEFTSIB          0x08
 #define        XFS_BB_RIGHTSIB         0x10
+#define        XFS_BB_BLKNO            0x20
 #define        XFS_BB_NUM_BITS         5
 #define        XFS_BB_ALL_BITS         ((1 << XFS_BB_NUM_BITS) - 1)
-
-/*
- * Magic numbers for btree blocks.
- */
-extern const __uint32_t        xfs_magics[];
+#define        XFS_BB_NUM_BITS_CRC     8
+#define        XFS_BB_ALL_BITS_CRC     ((1 << XFS_BB_NUM_BITS_CRC) - 1)
 
 /*
  * Generic stats interface
@@ -275,6 +296,7 @@ typedef struct xfs_btree_cur
 #define XFS_BTREE_LONG_PTRS            (1<<0)  /* pointers are 64bits long */
 #define XFS_BTREE_ROOT_IN_INODE                (1<<1)  /* root may be variable 
size */
 #define XFS_BTREE_LASTREC_UPDATE       (1<<2)  /* track last rec externally */
+#define XFS_BTREE_CRC_BLOCKS           (1<<3)  /* uses extended btree blocks */
 
 
 #define        XFS_BTREE_NOERROR       0
@@ -412,8 +434,20 @@ xfs_btree_init_block(
        __u32           magic,
        __u16           level,
        __u16           numrecs,
+       __u64           owner,
        unsigned int    flags);
 
+void
+xfs_btree_init_block_int(
+       struct xfs_mount        *mp,
+       struct xfs_btree_block  *buf,
+       xfs_daddr_t             blkno,
+       __u32                   magic,
+       __u16                   level,
+       __u16                   numrecs,
+       __u64                   owner,
+       unsigned int            flags);
+
 /*
  * Common btree core entry points.
  */
@@ -427,6 +461,14 @@ int xfs_btree_delete(struct xfs_btree_cur *, int *);
 int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *);
 
 /*
+ * btree block CRC helpers
+ */
+void xfs_btree_lblock_calc_crc(struct xfs_buf *);
+bool xfs_btree_lblock_verify_crc(struct xfs_buf *);
+void xfs_btree_sblock_calc_crc(struct xfs_buf *);
+bool xfs_btree_sblock_verify_crc(struct xfs_buf *);
+
+/*
  * Internal btree helpers also used by xfs_bmap.c.
  */
 void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int);
diff --git a/include/xfs_buf_item.h b/include/xfs_buf_item.h
index ee36c88..101ef83 100644
--- a/include/xfs_buf_item.h
+++ b/include/xfs_buf_item.h
@@ -24,19 +24,33 @@ extern kmem_zone_t  *xfs_buf_item_zone;
  * This flag indicates that the buffer contains on disk inodes
  * and requires special recovery handling.
  */
-#define        XFS_BLF_INODE_BUF       0x1
+#define        XFS_BLF_INODE_BUF       (1<<0)
 /*
  * This flag indicates that the buffer should not be replayed
  * during recovery because its blocks are being freed.
  */
-#define        XFS_BLF_CANCEL          0x2
+#define        XFS_BLF_CANCEL          (1<<1)
+
 /*
  * This flag indicates that the buffer contains on disk
  * user or group dquots and may require special recovery handling.
  */
-#define        XFS_BLF_UDQUOT_BUF      0x4
-#define XFS_BLF_PDQUOT_BUF     0x8
-#define        XFS_BLF_GDQUOT_BUF      0x10
+#define        XFS_BLF_UDQUOT_BUF      (1<<2)
+#define XFS_BLF_PDQUOT_BUF     (1<<3)
+#define        XFS_BLF_GDQUOT_BUF      (1<<4)
+
+/*
+ * all buffers now need flags to tell recovery where the magic number
+ * is so that it can verify and calculate the CRCs on the buffer correctly
+ * once the changes have been replayed into the buffer.
+ */
+#define XFS_BLF_BTREE_BUF      (1<<5)
+
+#define XFS_BLF_TYPE_MASK      \
+               (XFS_BLF_UDQUOT_BUF | \
+                XFS_BLF_PDQUOT_BUF | \
+                XFS_BLF_GDQUOT_BUF | \
+                XFS_BLF_BTREE_BUF)
 
 #define        XFS_BLF_CHUNK           128
 #define        XFS_BLF_SHIFT           7
diff --git a/include/xfs_dinode.h b/include/xfs_dinode.h
index 88a3368..6b5bd17 100644
--- a/include/xfs_dinode.h
+++ b/include/xfs_dinode.h
@@ -107,8 +107,8 @@ typedef enum xfs_dinode_fmt {
 #define XFS_LITINO(mp, version) \
        ((int)(((mp)->m_sb.sb_inodesize) - sizeof(struct xfs_dinode)))
 
-#define        XFS_BROOT_SIZE_ADJ      \
-       (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
+#define XFS_BROOT_SIZE_ADJ(ip) \
+       (XFS_BMBT_BLOCK_LEN((ip)->i_mount) - sizeof(xfs_bmdr_block_t))
 
 /*
  * Inode data & attribute fork sizes, per inode.
diff --git a/include/xfs_ialloc_btree.h b/include/xfs_ialloc_btree.h
index 25c0239..a1bfa7a 100644
--- a/include/xfs_ialloc_btree.h
+++ b/include/xfs_ialloc_btree.h
@@ -29,7 +29,8 @@ struct xfs_mount;
 /*
  * There is a btree for the inode map per allocation group.
  */
-#define        XFS_IBT_MAGIC   0x49414254      /* 'IABT' */
+#define        XFS_IBT_MAGIC           0x49414254      /* 'IABT' */
+#define        XFS_IBT_CRC_MAGIC       0x49414233      /* 'IAB3' */
 
 typedef        __uint64_t      xfs_inofree_t;
 #define        XFS_INODES_PER_CHUNK            (NBBY * sizeof(xfs_inofree_t))
@@ -76,10 +77,11 @@ typedef __be32 xfs_inobt_ptr_t;
 
 /*
  * Btree block header size depends on a superblock flag.
- *
- * (not quite yet, but soon)
  */
-#define XFS_INOBT_BLOCK_LEN(mp)        XFS_BTREE_SBLOCK_LEN
+#define XFS_INOBT_BLOCK_LEN(mp) \
+       (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
+        XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \
+        XFS_BTREE_SBLOCK_LEN)
 
 /*
  * Record, key, and pointer address macros for btree blocks.
diff --git a/include/xfs_trans.h b/include/xfs_trans.h
index acf1381..a9bd826 100644
--- a/include/xfs_trans.h
+++ b/include/xfs_trans.h
@@ -500,6 +500,8 @@ void                xfs_trans_inode_buf(xfs_trans_t *, 
struct xfs_buf *);
 void           xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
 void           xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
+void           xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *,
+                                      uint);
 void           xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
 void           xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
 void           xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index e75edd0..e9cc7b1 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -323,17 +323,17 @@ libxfs_bcompare(struct cache_node *node, cache_key_t key)
 
 #ifdef IO_BCOMPARE_CHECK
        if (bp->b_dev == bkey->device &&
-           bp->b_blkno == bkey->blkno &&
+           bp->b_bn == bkey->blkno &&
            bp->b_bcount != BBTOB(bkey->bblen))
                fprintf(stderr, "%lx: Badness in key lookup (length)\n"
                        "bp=(bno 0x%llx, len %u bytes) key=(bno 0x%llx, len %u 
bytes)\n",
                        pthread_self(),
-                       (unsigned long long)bp->b_blkno, (int)bp->b_bcount,
+                       (unsigned long long)bp->b_bn, (int)bp->b_bcount,
                        (unsigned long long)bkey->blkno, BBTOB(bkey->bblen));
 #endif
 
        return (bp->b_dev == bkey->device &&
-               bp->b_blkno == bkey->blkno &&
+               bp->b_bn == bkey->blkno &&
                bp->b_bcount == BBTOB(bkey->bblen));
 }
 
@@ -341,7 +341,7 @@ void
 libxfs_bprint(xfs_buf_t *bp)
 {
        fprintf(stderr, "Buffer 0x%p blkno=%llu bytes=%u flags=0x%x count=%u\n",
-               bp, (unsigned long long)bp->b_blkno, (unsigned)bp->b_bcount,
+               bp, (unsigned long long)bp->b_bn, (unsigned)bp->b_bcount,
                bp->b_flags, bp->b_node.cn_count);
 }
 
@@ -349,7 +349,7 @@ static void
 __initbuf(xfs_buf_t *bp, dev_t device, xfs_daddr_t bno, unsigned int bytes)
 {
        bp->b_flags = 0;
-       bp->b_blkno = bno;
+       bp->b_bn = bno;
        bp->b_bcount = bytes;
        bp->b_length = BTOBB(bytes);
        bp->b_dev = device;
@@ -613,7 +613,7 @@ libxfs_purgebuf(xfs_buf_t *bp)
        struct xfs_bufkey key = {0};
 
        key.device = bp->b_dev;
-       key.blkno = bp->b_blkno;
+       key.blkno = bp->b_bn;
        key.bblen = bp->b_bcount >> BBSHIFT;
 
        cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp);
@@ -669,7 +669,7 @@ libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t 
*bp, int len, int flags)
        error = __read_buf(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno), 
flags);
        if (!error &&
            bp->b_dev == dev &&
-           bp->b_blkno == blkno &&
+           bp->b_bn == blkno &&
            bp->b_bcount == bytes)
                bp->b_flags |= LIBXFS_B_UPTODATE;
 #ifdef IO_DEBUG
@@ -736,7 +736,7 @@ libxfs_readbuf_map(dev_t dev, struct xfs_buf_map *map, int 
nmaps, int flags)
 #ifdef IO_DEBUG
        printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n",
                pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error,
-               (long long)LIBXFS_BBTOOFF64(bp->b_blkno), (long 
long)bp->b_blkno, bp);
+               (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp);
 #endif
        return bp;
 }
@@ -772,7 +772,7 @@ libxfs_writebufr(xfs_buf_t *bp)
 
        if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) {
                error = __write_buf(fd, bp->b_addr, bp->b_bcount,
-                                   LIBXFS_BBTOOFF64(bp->b_blkno), bp->b_flags);
+                                   LIBXFS_BBTOOFF64(bp->b_bn), bp->b_flags);
        } else {
                int     i;
                char    *buf = bp->b_addr;
@@ -794,8 +794,8 @@ libxfs_writebufr(xfs_buf_t *bp)
 #ifdef IO_DEBUG
        printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p\n",
                        pthread_self(), __FUNCTION__, bp->b_bcount,
-                       (long long)LIBXFS_BBTOOFF64(bp->b_blkno),
-                       (long long)bp->b_blkno, bp);
+                       (long long)LIBXFS_BBTOOFF64(bp->b_bn),
+                       (long long)bp->b_bn, bp);
 #endif
        if (!error) {
                bp->b_flags |= LIBXFS_B_UPTODATE;
@@ -826,7 +826,7 @@ libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void 
*data, int flags)
        if (boff + len > bp->b_bcount) {
                printf("Badness, iomove out of range!\n"
                        "bp=(bno 0x%llx, bytes %u) range=(boff %u, bytes %u)\n",
-                       (long long)bp->b_blkno, bp->b_bcount, boff, len);
+                       (long long)bp->b_bn, bp->b_bcount, boff, len);
                abort();
        }
 #endif
diff --git a/libxfs/xfs.h b/libxfs/xfs.h
index 9fbe261..b3b45bb 100644
--- a/libxfs/xfs.h
+++ b/libxfs/xfs.h
@@ -249,6 +249,7 @@ roundup_pow_of_two(uint v)
 #define        xfs_trans_agblocks_delta(tp, d)
 #define        xfs_trans_agflist_delta(tp, d)
 #define        xfs_trans_agbtree_delta(tp, d)
+#define xfs_trans_buf_set_type(tp, bp, t)
 
 #define xfs_buf_readahead(a,b,c,ops)           ((void) 0)      /* no readahead 
*/
 #define xfs_buf_readahead_map(a,b,c,ops)       ((void) 0)      /* no readahead 
*/
@@ -314,6 +315,9 @@ do { \
 #define xfs_trans_unreserve_quota_nblks(t,i,b,n,f)     ((void) 0)
 #define xfs_qm_dqattach(i,f)                           (0)
 
+#define uuid_copy(s,d)         platform_uuid_copy((s),(d))
+#define uuid_equal(s,d)                (platform_uuid_compare((s),(d)) == 0)
+
 /*
  * Prototypes for kernel static functions that are aren't in their
  * associated header files
diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
index a751c37..1ee1f48 100644
--- a/libxfs/xfs_alloc_btree.c
+++ b/libxfs/xfs_alloc_btree.c
@@ -253,7 +253,7 @@ xfs_allocbt_key_diff(
        return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
 }
 
-static void
+static bool
 xfs_allocbt_verify(
        struct xfs_buf          *bp)
 {
@@ -261,66 +261,98 @@ xfs_allocbt_verify(
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        struct xfs_perag        *pag = bp->b_pag;
        unsigned int            level;
-       int                     sblock_ok; /* block passes checks */
 
        /*
         * magic number and level verification
         *
-        * During growfs operations, we can't verify the exact level as the
-        * perag is not fully initialised and hence not attached to the buffer.
-        * In this case, check against the maximum tree depth.
+        * During growfs operations, we can't verify the exact level or owner as
+        * the perag is not fully initialised and hence not attached to the
+        * buffer.  In this case, check against the maximum tree depth.
         */
        level = be16_to_cpu(block->bb_level);
        switch (cpu_to_be32(block->bb_magic)) {
+       case XFS_ABTB_CRC_MAGIC:
+               if (!xfs_sb_version_hascrc(&mp->m_sb))
+                       return false;
+               if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+                       return false;
+               if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
+                       return false;
+               if (pag &&
+                   be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+                       return false;
+               /* fall through */
        case XFS_ABTB_MAGIC:
-               if (pag)
-                       sblock_ok = level < pag->pagf_levels[XFS_BTNUM_BNOi];
-               else
-                       sblock_ok = level < mp->m_ag_maxlevels;
+               if (pag) {
+                       if (level >= pag->pagf_levels[XFS_BTNUM_BNOi])
+                               return false;
+               } else if (level >= mp->m_ag_maxlevels)
+                       return false;
                break;
+       case XFS_ABTC_CRC_MAGIC:
+               if (!xfs_sb_version_hascrc(&mp->m_sb))
+                       return false;
+               if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+                       return false;
+               if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
+                       return false;
+               if (pag &&
+                   be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+                       return false;
+               /* fall through */
        case XFS_ABTC_MAGIC:
-               if (pag)
-                       sblock_ok = level < pag->pagf_levels[XFS_BTNUM_CNTi];
-               else
-                       sblock_ok = level < mp->m_ag_maxlevels;
+               if (pag) {
+                       if (level >= pag->pagf_levels[XFS_BTNUM_CNTi])
+                               return false;
+               } else if (level >= mp->m_ag_maxlevels)
+                       return false;
                break;
        default:
-               sblock_ok = 0;
-               break;
+               return false;
        }
 
        /* numrecs verification */
-       sblock_ok = sblock_ok &&
-               be16_to_cpu(block->bb_numrecs) <= mp->m_alloc_mxr[level != 0];
+       if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[level != 0])
+               return false;
 
        /* sibling pointer verification */
-       sblock_ok = sblock_ok &&
-               (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) ||
-                be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) 
&&
-               block->bb_u.s.bb_leftsib &&
-               (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
-                be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) 
&&
-               block->bb_u.s.bb_rightsib;
-
-       if (!sblock_ok) {
-               trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
-               xfs_buf_ioerror(bp, EFSCORRUPTED);
-       }
+       if (!block->bb_u.s.bb_leftsib ||
+           (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
+            block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
+               return false;
+       if (!block->bb_u.s.bb_rightsib ||
+           (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
+            block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
+               return false;
+
+       return true;
 }
 
 static void
 xfs_allocbt_read_verify(
        struct xfs_buf  *bp)
 {
-       xfs_allocbt_verify(bp);
+       if (!(xfs_btree_sblock_verify_crc(bp) &&
+             xfs_allocbt_verify(bp))) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    bp->b_target->bt_mount, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
 }
 
 static void
 xfs_allocbt_write_verify(
        struct xfs_buf  *bp)
 {
-       xfs_allocbt_verify(bp);
+       if (!xfs_allocbt_verify(bp)) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    bp->b_target->bt_mount, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
+       xfs_btree_sblock_calc_crc(bp);
+
 }
 
 const struct xfs_buf_ops xfs_allocbt_buf_ops = {
@@ -498,6 +530,9 @@ xfs_allocbt_init_cursor(
        cur->bc_private.a.agbp = agbp;
        cur->bc_private.a.agno = agno;
 
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
+
        return cur;
 }
 
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 426130f..85cb31d 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -201,7 +201,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
                                return 0;
                        return dp->i_d.di_forkoff;
                }
-               dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
+               dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
                break;
        }
 
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index c8232a9..5e736a5 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -407,11 +407,15 @@ xfs_bmap_sanity_check(
 {
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
 
-       if (block->bb_magic != cpu_to_be32(XFS_BMAP_MAGIC) ||
-           be16_to_cpu(block->bb_level) != level ||
+       if (block->bb_magic != cpu_to_be32(XFS_BMAP_CRC_MAGIC) &&
+           block->bb_magic != cpu_to_be32(XFS_BMAP_MAGIC))
+               return 0;
+
+       if (be16_to_cpu(block->bb_level) != level ||
            be16_to_cpu(block->bb_numrecs) == 0 ||
            be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0])
                return 0;
+
        return 1;
 }
 
@@ -914,6 +918,7 @@ xfs_bmap_extents_to_btree(
        xfs_extnum_t            nextents;       /* number of file extents */
        xfs_bmbt_ptr_t          *pp;            /* root block address pointer */
 
+       mp = ip->i_mount;
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS);
 
@@ -927,16 +932,18 @@ xfs_bmap_extents_to_btree(
         * Fill in the root.
         */
        block = ifp->if_broot;
-       block->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
-       block->bb_level = cpu_to_be16(1);
-       block->bb_numrecs = cpu_to_be16(1);
-       block->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
-       block->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL,
+                                XFS_BMAP_CRC_MAGIC, 1, 1, ip->i_ino,
+                                XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS);
+       else
+               xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL,
+                                XFS_BMAP_MAGIC, 1, 1, ip->i_ino,
+                                XFS_BTREE_LONG_PTRS);
 
        /*
         * Need a cursor.  Can't allocate until bb_level is filled in.
         */
-       mp = ip->i_mount;
        cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
        cur->bc_private.b.firstblock = *firstblock;
        cur->bc_private.b.flist = flist;
@@ -985,10 +992,15 @@ xfs_bmap_extents_to_btree(
         */
        abp->b_ops = &xfs_bmbt_buf_ops;
        ablock = XFS_BUF_TO_BLOCK(abp);
-       ablock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
-       ablock->bb_level = 0;
-       ablock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
-       ablock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               xfs_btree_init_block_int(mp, ablock, abp->b_bn,
+                               XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino,
+                               XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS);
+       else
+               xfs_btree_init_block_int(mp, ablock, abp->b_bn,
+                               XFS_BMAP_MAGIC, 0, 0, ip->i_ino,
+                               XFS_BTREE_LONG_PTRS);
+
        arp = XFS_BMBT_REC_ADDR(mp, ablock, 1);
        nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
        for (cnt = i = 0; i < nextents; i++) {
@@ -1016,8 +1028,8 @@ xfs_bmap_extents_to_btree(
         * Do all this logging at the end so that
         * the root is at the right level.
         */
-       xfs_btree_log_block(cur, abp, XFS_BB_ALL_BITS);
        xfs_btree_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs));
+       xfs_btree_log_block(cur, abp, XFS_BB_ALL_BITS);
        ASSERT(*curp == NULL);
        *curp = cur;
        *logflagsp = XFS_ILOG_CORE | xfs_ilog_fbroot(whichfork);
@@ -1038,7 +1050,8 @@ xfs_bmap_local_to_extents(
        xfs_extlen_t    total,          /* total blocks needed by transaction */
        int             *logflagsp,     /* inode logging flags */
        int             whichfork,
-       void            (*init_fn)(struct xfs_buf *bp,
+       void            (*init_fn)(struct xfs_trans *tp,
+                                  struct xfs_buf *bp,
                                   struct xfs_inode *ip,
                                   struct xfs_ifork *ifp))
 {
@@ -1090,7 +1103,7 @@ xfs_bmap_local_to_extents(
                bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
 
                /* initialise the block and copy the data */
-               init_fn(bp, ip, ifp);
+               init_fn(tp, bp, ip, ifp);
 
                /* account for the change in fork size and log everything */
                xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
@@ -1197,16 +1210,19 @@ xfs_bmap_add_attrfork_extents(
  */
 STATIC void
 xfs_bmap_local_to_extents_init_fn(
+       struct xfs_trans        *tp,
        struct xfs_buf          *bp,
        struct xfs_inode        *ip,
        struct xfs_ifork        *ifp)
 {
        bp->b_ops = &xfs_bmbt_buf_ops;
        memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
+       xfs_trans_buf_set_type(tp, bp, XFS_BLF_BTREE_BUF);
 }
 
 STATIC void
 xfs_symlink_local_to_remote(
+       struct xfs_trans        *tp,
        struct xfs_buf          *bp,
        struct xfs_inode        *ip,
        struct xfs_ifork        *ifp)
@@ -1225,8 +1241,7 @@ xfs_symlink_local_to_remote(
  *
  * XXX (dgc): investigate whether directory conversion can use the generic
  * formatting callout. It should be possible - it's just a very complex
- * formatter. it would also require passing the transaction through to the init
- * function.
+ * formatter.
  */
 STATIC int                                     /* error */
 xfs_bmap_add_attrfork_local(
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 836f52f..473db4a 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -38,24 +38,31 @@ xfs_extent_state(
  */
 void
 xfs_bmdr_to_bmbt(
-       struct xfs_mount        *mp,
+       struct xfs_inode        *ip,
        xfs_bmdr_block_t        *dblock,
        int                     dblocklen,
        struct xfs_btree_block  *rblock,
        int                     rblocklen)
 {
+       struct xfs_mount        *mp = ip->i_mount;
        int                     dmxr;
        xfs_bmbt_key_t          *fkp;
        __be64                  *fpp;
        xfs_bmbt_key_t          *tkp;
        __be64                  *tpp;
 
-       rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL,
+                                XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino,
+                                XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS);
+       else
+               xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL,
+                                XFS_BMAP_MAGIC, 0, 0, ip->i_ino,
+                                XFS_BTREE_LONG_PTRS);
+
        rblock->bb_level = dblock->bb_level;
        ASSERT(be16_to_cpu(rblock->bb_level) > 0);
        rblock->bb_numrecs = dblock->bb_numrecs;
-       rblock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
-       rblock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
        dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
        fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
        tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
@@ -403,7 +410,13 @@ xfs_bmbt_to_bmdr(
        xfs_bmbt_key_t          *tkp;
        __be64                  *tpp;
 
-       ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC));
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
+               ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
+               ASSERT(rblock->bb_u.l.bb_blkno ==
+                      cpu_to_be64(XFS_BUF_DADDR_NULL));
+       } else
+               ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC));
        ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO));
        ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO));
        ASSERT(rblock->bb_level != 0);
@@ -687,45 +700,59 @@ xfs_bmbt_key_diff(
                                      cur->bc_rec.b.br_startoff;
 }
 
-static void
+static bool
 xfs_bmbt_verify(
        struct xfs_buf          *bp)
 {
        struct xfs_mount        *mp = bp->b_target->bt_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
        unsigned int            level;
-       int                     lblock_ok; /* block passes checks */
 
-       /* magic number and level verification.
+       switch (be32_to_cpu(block->bb_magic)) {
+       case XFS_BMAP_CRC_MAGIC:
+               if (!xfs_sb_version_hascrc(&mp->m_sb))
+                       return false;
+               if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
+                       return false;
+               if (block->bb_u.l.bb_blkno != cpu_to_be64(bp->b_bn))
+                       return false;
+               /*
+                * XXX: need a better way of verifying the owner here. Right now
+                * just make sure there has been one set.
+                */
+               if (be64_to_cpu(block->bb_u.l.bb_owner) == 0)
+                       return false;
+               /* fall through */
+       case XFS_BMAP_MAGIC:
+               break;
+       default:
+               return false;
+       }
+
+       /*
+        * numrecs and level verification.
         *
-        * We don't know waht fork we belong to, so just verify that the level
+        * We don't know what fork we belong to, so just verify that the level
         * is less than the maximum of the two. Later checks will be more
         * precise.
         */
        level = be16_to_cpu(block->bb_level);
-       lblock_ok = block->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC) &&
-                   level < MAX(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]);
-
-       /* numrecs verification */
-       lblock_ok = lblock_ok &&
-               be16_to_cpu(block->bb_numrecs) <= mp->m_bmap_dmxr[level != 0];
+       if (level > MAX(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]))
+               return false;
+       if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0])
+               return false;
 
        /* sibling pointer verification */
-       lblock_ok = lblock_ok &&
-               block->bb_u.l.bb_leftsib &&
-               (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) ||
-                XFS_FSB_SANITY_CHECK(mp,
-                       be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
-               block->bb_u.l.bb_rightsib &&
-               (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) ||
-                XFS_FSB_SANITY_CHECK(mp,
-                       be64_to_cpu(block->bb_u.l.bb_rightsib)));
-
-       if (!lblock_ok) {
-               trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
-               xfs_buf_ioerror(bp, EFSCORRUPTED);
-       }
+       if (!block->bb_u.l.bb_leftsib ||
+           (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLDFSBNO) &&
+            !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib))))
+               return false;
+       if (!block->bb_u.l.bb_rightsib ||
+           (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLDFSBNO) &&
+            !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib))))
+               return false;
+
+       return true;
 }
 
 static void
@@ -733,13 +760,29 @@ xfs_bmbt_read_verify(
        struct xfs_buf  *bp)
 {
        xfs_bmbt_verify(bp);
+       if (!(xfs_btree_lblock_verify_crc(bp) &&
+             xfs_bmbt_verify(bp))) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    bp->b_target->bt_mount, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
+
 }
 
 static void
 xfs_bmbt_write_verify(
        struct xfs_buf  *bp)
 {
-       xfs_bmbt_verify(bp);
+       if (!xfs_bmbt_verify(bp)) {
+               xfs_warn(bp->b_target->bt_mount, "bmbt daddr 0x%llx failed", 
bp->b_bn);
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    bp->b_target->bt_mount, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+               return;
+       }
+       xfs_btree_lblock_calc_crc(bp);
 }
 
 const struct xfs_buf_ops xfs_bmbt_buf_ops = {
@@ -913,6 +956,8 @@ xfs_bmbt_init_cursor(
 
        cur->bc_ops = &xfs_bmbt_ops;
        cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
 
        cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
        cur->bc_private.b.ip = ip;
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index c35269b..a7c19e9 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -26,9 +26,13 @@ kmem_zone_t  *xfs_btree_cur_zone;
 /*
  * Btree magic numbers.
  */
-const __uint32_t xfs_magics[XFS_BTNUM_MAX] = {
-       XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC
+static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
+       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC },
+       { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
+         XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC }
 };
+#define xfs_btree_magic(cur) \
+       xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
 
 
 STATIC int                             /* error (0 or EFSCORRUPTED) */
@@ -38,30 +42,38 @@ xfs_btree_check_lblock(
        int                     level,  /* level of the btree block */
        struct xfs_buf          *bp)    /* buffer for block, if any */
 {
-       int                     lblock_ok; /* block passes checks */
+       int                     lblock_ok = 1; /* block passes checks */
        struct xfs_mount        *mp;    /* file system mount point */
 
        mp = cur->bc_mp;
-       lblock_ok =
-               be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] &&
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               lblock_ok = lblock_ok &&
+                       uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
+                       block->bb_u.l.bb_blkno == cpu_to_be64(
+                               bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
+       }
+
+       lblock_ok = lblock_ok &&
+               be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) &&
                be16_to_cpu(block->bb_level) == level &&
                be16_to_cpu(block->bb_numrecs) <=
                        cur->bc_ops->get_maxrecs(cur, level) &&
                block->bb_u.l.bb_leftsib &&
                (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) ||
                 XFS_FSB_SANITY_CHECK(mp,
-                       be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
+                       be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
                block->bb_u.l.bb_rightsib &&
                (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) ||
                 XFS_FSB_SANITY_CHECK(mp,
-                       be64_to_cpu(block->bb_u.l.bb_rightsib)));
+                       be64_to_cpu(block->bb_u.l.bb_rightsib)));
+
        if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp,
                        XFS_ERRTAG_BTREE_CHECK_LBLOCK,
                        XFS_RANDOM_BTREE_CHECK_LBLOCK))) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_ERROR_REPORT("xfs_btree_check_lblock", XFS_ERRLEVEL_LOW,
-                                mp);
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                return XFS_ERROR(EFSCORRUPTED);
        }
        return 0;
@@ -74,16 +86,26 @@ xfs_btree_check_sblock(
        int                     level,  /* level of the btree block */
        struct xfs_buf          *bp)    /* buffer containing block */
 {
+       struct xfs_mount        *mp;    /* file system mount point */
        struct xfs_buf          *agbp;  /* buffer for ag. freespace struct */
        struct xfs_agf          *agf;   /* ag. freespace structure */
        xfs_agblock_t           agflen; /* native ag. freespace length */
-       int                     sblock_ok; /* block passes checks */
+       int                     sblock_ok = 1; /* block passes checks */
 
+       mp = cur->bc_mp;
        agbp = cur->bc_private.a.agbp;
        agf = XFS_BUF_TO_AGF(agbp);
        agflen = be32_to_cpu(agf->agf_length);
-       sblock_ok =
-               be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] &&
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               sblock_ok = sblock_ok &&
+                       uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
+                       block->bb_u.s.bb_blkno == cpu_to_be64(
+                               bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
+       }
+
+       sblock_ok = sblock_ok &&
+               be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) &&
                be16_to_cpu(block->bb_level) == level &&
                be16_to_cpu(block->bb_numrecs) <=
                        cur->bc_ops->get_maxrecs(cur, level) &&
@@ -93,13 +115,13 @@ xfs_btree_check_sblock(
                (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
                 be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) &&
                block->bb_u.s.bb_rightsib;
-       if (unlikely(XFS_TEST_ERROR(!sblock_ok, cur->bc_mp,
+
+       if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp,
                        XFS_ERRTAG_BTREE_CHECK_SBLOCK,
                        XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_CORRUPTION_ERROR("xfs_btree_check_sblock",
-                       XFS_ERRLEVEL_LOW, cur->bc_mp, block);
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                return XFS_ERROR(EFSCORRUPTED);
        }
        return 0;
@@ -178,6 +200,72 @@ xfs_btree_check_ptr(
 #endif
 
 /*
+ * Calculate CRC on the whole btree block and stuff it into the
+ * long-form btree header.
+ *
+ * Prior to calculting the CRC, pull the LSN out of the buffer log item and put
+ * it into the buffer so recovery knows what the last modifcation was that made
+ * it to disk.
+ */
+void
+xfs_btree_lblock_calc_crc(
+       struct xfs_buf          *bp)
+{
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+
+       if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+               return;
+       if (bip)
+               block->bb_u.l.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        XFS_BTREE_LBLOCK_CRC_OFF);
+}
+
+bool
+xfs_btree_lblock_verify_crc(
+       struct xfs_buf          *bp)
+{
+       if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+               return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
+                                       XFS_BTREE_LBLOCK_CRC_OFF);
+       return true;
+}
+
+/*
+ * Calculate CRC on the whole btree block and stuff it into the
+ * short-form btree header.
+ *
+ * Prior to calculting the CRC, pull the LSN out of the buffer log item and put
+ * it into the buffer so recovery knows what the last modifcation was that made
+ * it to disk.
+ */
+void
+xfs_btree_sblock_calc_crc(
+       struct xfs_buf          *bp)
+{
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+
+       if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+               return;
+       if (bip)
+               block->bb_u.s.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        XFS_BTREE_SBLOCK_CRC_OFF);
+}
+
+bool
+xfs_btree_sblock_verify_crc(
+       struct xfs_buf          *bp)
+{
+       if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+               return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
+                                       XFS_BTREE_SBLOCK_CRC_OFF);
+       return true;
+}
+
+/*
  * Delete the btree cursor.
  */
 void
@@ -261,10 +349,8 @@ xfs_btree_dup_cursor(
                                *ncur = NULL;
                                return error;
                        }
-                       new->bc_bufs[i] = bp;
-                       ASSERT(!xfs_buf_geterror(bp));
-               } else
-                       new->bc_bufs[i] = NULL;
+               }
+               new->bc_bufs[i] = bp;
        }
        *ncur = new;
        return 0;
@@ -305,9 +391,17 @@ xfs_btree_dup_cursor(
  */
 static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur)
 {
-       return (cur->bc_flags & XFS_BTREE_LONG_PTRS) ?
-               XFS_BTREE_LBLOCK_LEN :
-               XFS_BTREE_SBLOCK_LEN;
+       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_CRC_BLOCKS)
+               len += XFS_BTREE_CRCBLOCK_ADD;
+
+       return len;
 }
 
 /*
@@ -807,43 +901,85 @@ xfs_btree_set_sibling(
 }
 
 void
+xfs_btree_init_block_int(
+       struct xfs_mount        *mp,
+       struct xfs_btree_block  *buf,
+       xfs_daddr_t             blkno,
+       __u32                   magic,
+       __u16                   level,
+       __u16                   numrecs,
+       __u64                   owner,
+       unsigned int            flags)
+{
+       buf->bb_magic = cpu_to_be32(magic);
+       buf->bb_level = cpu_to_be16(level);
+       buf->bb_numrecs = cpu_to_be16(numrecs);
+
+       if (flags & XFS_BTREE_LONG_PTRS) {
+               buf->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
+               buf->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
+               if (flags & XFS_BTREE_CRC_BLOCKS) {
+                       buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
+                       buf->bb_u.l.bb_owner = cpu_to_be64(owner);
+                       uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+                       buf->bb_u.l.bb_pad = 0;
+               }
+       } else {
+               /* owner is a 32 bit value on short blocks */
+               __u32 __owner = (__u32)owner;
+
+               buf->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
+               buf->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
+               if (flags & XFS_BTREE_CRC_BLOCKS) {
+                       buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
+                       buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
+                       uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+               }
+       }
+}
+
+void
 xfs_btree_init_block(
        struct xfs_mount *mp,
        struct xfs_buf  *bp,
        __u32           magic,
        __u16           level,
        __u16           numrecs,
+       __u64           owner,
        unsigned int    flags)
 {
-       struct xfs_btree_block  *new = XFS_BUF_TO_BLOCK(bp);
-
-       new->bb_magic = cpu_to_be32(magic);
-       new->bb_level = cpu_to_be16(level);
-       new->bb_numrecs = cpu_to_be16(numrecs);
-
-       if (flags & XFS_BTREE_LONG_PTRS) {
-               new->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
-               new->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
-       } else {
-               new->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
-               new->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
-       }
+       xfs_btree_init_block_int(mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
+                                magic, level, numrecs, owner, flags);
 }
 
 STATIC void
 xfs_btree_init_block_cur(
        struct xfs_btree_cur    *cur,
+       struct xfs_buf          *bp,
        int                     level,
-       int                     numrecs,
-       struct xfs_buf          *bp)
+       int                     numrecs)
 {
-       xfs_btree_init_block(cur->bc_mp, bp, xfs_magics[cur->bc_btnum],
-                              level, numrecs, cur->bc_flags);
+       __u64 owner;
+
+       /*
+        * we can pull the owner from the cursor right now as the different
+        * owners align directly with the pointer size of the btree. This may
+        * change in future, but is safe for current users of the generic btree
+        * code.
+        */
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+               owner = cur->bc_private.b.ip->i_ino;
+       else
+               owner = cur->bc_private.a.agno;
+
+       xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
+                                xfs_btree_magic(cur), level, numrecs,
+                                owner, cur->bc_flags);
 }
 
 /*
  * Return true if ptr is the last record in the btree and
- * we need to track updateÑ to this record.  The decision
+ * we need to track updates to this record.  The decision
  * will be further refined in the update_lastrec method.
  */
 STATIC int
@@ -1091,6 +1227,7 @@ xfs_btree_log_keys(
        XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
 
        if (bp) {
+               xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
                xfs_trans_log_buf(cur->bc_tp, bp,
                                  xfs_btree_key_offset(cur, first),
                                  xfs_btree_key_offset(cur, last + 1) - 1);
@@ -1115,6 +1252,7 @@ xfs_btree_log_recs(
        XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
 
+       xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
        xfs_trans_log_buf(cur->bc_tp, bp,
                          xfs_btree_rec_offset(cur, first),
                          xfs_btree_rec_offset(cur, last + 1) - 1);
@@ -1139,6 +1277,7 @@ xfs_btree_log_ptrs(
                struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
                int                     level = xfs_btree_get_level(block);
 
+               xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
                xfs_trans_log_buf(cur->bc_tp, bp,
                                xfs_btree_ptr_offset(cur, first, level),
                                xfs_btree_ptr_offset(cur, last + 1, level) - 1);
@@ -1167,7 +1306,12 @@ xfs_btree_log_block(
                offsetof(struct xfs_btree_block, bb_numrecs),
                offsetof(struct xfs_btree_block, bb_u.s.bb_leftsib),
                offsetof(struct xfs_btree_block, bb_u.s.bb_rightsib),
-               XFS_BTREE_SBLOCK_LEN
+               offsetof(struct xfs_btree_block, bb_u.s.bb_blkno),
+               offsetof(struct xfs_btree_block, bb_u.s.bb_lsn),
+               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
        };
        static const short      loffsets[] = {  /* table of offsets (long) */
                offsetof(struct xfs_btree_block, bb_magic),
@@ -1175,17 +1319,40 @@ xfs_btree_log_block(
                offsetof(struct xfs_btree_block, bb_numrecs),
                offsetof(struct xfs_btree_block, bb_u.l.bb_leftsib),
                offsetof(struct xfs_btree_block, bb_u.l.bb_rightsib),
-               XFS_BTREE_LBLOCK_LEN
+               offsetof(struct xfs_btree_block, bb_u.l.bb_blkno),
+               offsetof(struct xfs_btree_block, bb_u.l.bb_lsn),
+               offsetof(struct xfs_btree_block, bb_u.l.bb_uuid),
+               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_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_TRACE_ARGBI(cur, bp, fields);
 
        if (bp) {
+               int nbits;
+
+               if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+                       /*
+                        * We don't log the CRC when updating a btree
+                        * block but instead recreate it during log
+                        * recovery.  As the log buffers have checksums
+                        * of their this is safe and avoids logging a crc
+                        * update in a lot of places.
+                        */
+                       if (fields == XFS_BB_ALL_BITS)
+                               fields = XFS_BB_ALL_BITS_CRC;
+                       nbits = XFS_BB_NUM_BITS_CRC;
+               } else {
+                       nbits = XFS_BB_NUM_BITS;
+               }
                xfs_btree_offsets(fields,
                                  (cur->bc_flags & XFS_BTREE_LONG_PTRS) ?
                                        loffsets : soffsets,
-                                 XFS_BB_NUM_BITS, &first, &last);
+                                 nbits, &first, &last);
+               xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
                xfs_trans_log_buf(cur->bc_tp, bp, first, last);
        } else {
                xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
@@ -2148,7 +2315,7 @@ xfs_btree_split(
                goto error0;
 
        /* Fill in the btree header for the new right block. */
-       xfs_btree_init_block_cur(cur, xfs_btree_get_level(left), 0, rbp);
+       xfs_btree_init_block_cur(cur, rbp, xfs_btree_get_level(left), 0);
 
        /*
         * Split the entries between the old and the new block evenly.
@@ -2457,7 +2624,7 @@ xfs_btree_new_root(
                nptr = 2;
        }
        /* Fill in the new block's btree header and log it. */
-       xfs_btree_init_block_cur(cur, cur->bc_nlevels, 2, nbp);
+       xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2);
        xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS);
        ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) &&
                        !xfs_btree_ptr_is_null(cur, &rptr));
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 0bc24cc..ee036bf 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -163,52 +163,82 @@ xfs_inobt_key_diff(
                          cur->bc_rec.i.ir_startino;
 }
 
-void
+static int
 xfs_inobt_verify(
        struct xfs_buf          *bp)
 {
        struct xfs_mount        *mp = bp->b_target->bt_mount;
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       struct xfs_perag        *pag = bp->b_pag;
        unsigned int            level;
-       int                     sblock_ok; /* block passes checks */
 
-       /* magic number and level verification */
-       level = be16_to_cpu(block->bb_level);
-       sblock_ok = block->bb_magic == cpu_to_be32(XFS_IBT_MAGIC) &&
-                   level < mp->m_in_maxlevels;
+       /*
+        * During growfs operations, we can't verify the exact owner as the
+        * perag is not fully initialised and hence not attached to the buffer.
+        */
+       switch (be32_to_cpu(block->bb_magic)) {
+       case XFS_IBT_CRC_MAGIC:
+               if (!xfs_sb_version_hascrc(&mp->m_sb))
+                       return false;
+               if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+                       return false;
+               if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
+                       return false;
+               if (pag &&
+                   be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+                       return false;
+               /* fall through */
+       case XFS_IBT_MAGIC:
+               break;
+       default:
+               return 0;
+       }
 
-       /* numrecs verification */
-       sblock_ok = sblock_ok &&
-               be16_to_cpu(block->bb_numrecs) <= mp->m_inobt_mxr[level != 0];
+       /* numrecs and level verification */
+       level = be16_to_cpu(block->bb_level);
+       if (level >= mp->m_in_maxlevels)
+               return false;
+       if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[level != 0])
+               return false;
 
        /* sibling pointer verification */
-       sblock_ok = sblock_ok &&
-               (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) ||
-                be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) 
&&
-               block->bb_u.s.bb_leftsib &&
-               (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
-                be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) 
&&
-               block->bb_u.s.bb_rightsib;
-
-       if (!sblock_ok) {
-               trace_xfs_btree_corrupt(bp, _RET_IP_);
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
-               xfs_buf_ioerror(bp, EFSCORRUPTED);
-       }
+       if (!block->bb_u.s.bb_leftsib ||
+           (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
+            block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
+               return false;
+       if (!block->bb_u.s.bb_rightsib ||
+           (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
+            block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
+               return false;
+
+       return true;
 }
 
 static void
 xfs_inobt_read_verify(
        struct xfs_buf  *bp)
 {
-       xfs_inobt_verify(bp);
+       if (!(xfs_btree_sblock_verify_crc(bp) &&
+             xfs_inobt_verify(bp))) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    bp->b_target->bt_mount, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
 }
 
 static void
 xfs_inobt_write_verify(
        struct xfs_buf  *bp)
 {
-       xfs_inobt_verify(bp);
+       if (!xfs_inobt_verify(bp)) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    bp->b_target->bt_mount, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
+       xfs_btree_sblock_calc_crc(bp);
+
 }
 
 const struct xfs_buf_ops xfs_inobt_buf_ops = {
@@ -355,6 +385,8 @@ xfs_inobt_init_cursor(
        cur->bc_blocklog = mp->m_sb.sb_blocklog;
 
        cur->bc_ops = &xfs_inobt_ops;
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
 
        cur->bc_private.a.agbp = agbp;
        cur->bc_private.a.agno = agno;
diff --git a/libxfs/xfs_inode.c b/libxfs/xfs_inode.c
index 3cf2423..f9f792c 100644
--- a/libxfs/xfs_inode.c
+++ b/libxfs/xfs_inode.c
@@ -492,6 +492,7 @@ xfs_iformat_btree(
        xfs_dinode_t            *dip,
        int                     whichfork)
 {
+       struct xfs_mount        *mp = ip->i_mount;
        xfs_bmdr_block_t        *dfp;
        xfs_ifork_t             *ifp;
        /* REFERENCED */
@@ -500,7 +501,7 @@ xfs_iformat_btree(
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
        dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
-       size = XFS_BMAP_BROOT_SPACE(dfp);
+       size = XFS_BMAP_BROOT_SPACE(mp, dfp);
        nrecs = be16_to_cpu(dfp->bb_numrecs);
 
        /*
@@ -511,14 +512,14 @@ xfs_iformat_btree(
         * blocks.
         */
        if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
-                       XFS_IFORK_MAXEXT(ip, whichfork) ||
+                                       XFS_IFORK_MAXEXT(ip, whichfork) ||
                     XFS_BMDR_SPACE_CALC(nrecs) >
-                       XFS_DFORK_SIZE(dip, ip->i_mount, whichfork) ||
+                                       XFS_DFORK_SIZE(dip, mp, whichfork) ||
                     XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
-               xfs_warn(ip->i_mount, "corrupt inode %Lu (btree).",
-                       (unsigned long long) ip->i_ino);
+               xfs_warn(mp, "corrupt inode %Lu (btree).",
+                                       (unsigned long long) ip->i_ino);
                XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
-                                ip->i_mount, dip);
+                                        mp, dip);
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -529,8 +530,7 @@ xfs_iformat_btree(
         * Copy and convert from the on-disk structure
         * to the in-memory structure.
         */
-       xfs_bmdr_to_bmbt(ip->i_mount, dfp,
-                        XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
+       xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
                         ifp->if_broot, size);
        ifp->if_flags &= ~XFS_IFEXTENTS;
        ifp->if_flags |= XFS_IFBROOT;
@@ -813,7 +813,7 @@ xfs_iroot_realloc(
                 * allocate it now and get out.
                 */
                if (ifp->if_broot_bytes == 0) {
-                       new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff);
+                       new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
                        ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | 
KM_NOFS);
                        ifp->if_broot_bytes = (int)new_size;
                        return;
@@ -827,9 +827,9 @@ xfs_iroot_realloc(
                 */
                cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
                new_max = cur_max + rec_diff;
-               new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
+               new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
                ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
-                               (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* 
old size */
+                               XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max),
                                KM_SLEEP | KM_NOFS);
                op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
                                                     ifp->if_broot_bytes);
@@ -837,7 +837,7 @@ xfs_iroot_realloc(
                                                     (int)new_size);
                ifp->if_broot_bytes = (int)new_size;
                ASSERT(ifp->if_broot_bytes <=
-                       XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ);
+                       XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip));
                memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
                return;
        }
@@ -852,7 +852,7 @@ xfs_iroot_realloc(
        new_max = cur_max + rec_diff;
        ASSERT(new_max >= 0);
        if (new_max > 0)
-               new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
+               new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
        else
                new_size = 0;
        if (new_size > 0) {
@@ -860,7 +860,8 @@ xfs_iroot_realloc(
                /*
                 * First copy over the btree block header.
                 */
-               memcpy(new_broot, ifp->if_broot, XFS_BTREE_LBLOCK_LEN);
+               memcpy(new_broot, ifp->if_broot,
+                       XFS_BMBT_BLOCK_LEN(ip->i_mount));
        } else {
                new_broot = NULL;
                ifp->if_flags &= ~XFS_IFBROOT;
@@ -890,7 +891,7 @@ xfs_iroot_realloc(
        ifp->if_broot = new_broot;
        ifp->if_broot_bytes = (int)new_size;
        ASSERT(ifp->if_broot_bytes <=
-               XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ);
+               XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip));
        return;
 }
 
@@ -1161,7 +1162,7 @@ xfs_iflush_fork(
                        ASSERT(ifp->if_broot != NULL);
                        ASSERT(ifp->if_broot_bytes <=
                               (XFS_IFORK_SIZE(ip, whichfork) +
-                               XFS_BROOT_SIZE_ADJ));
+                               XFS_BROOT_SIZE_ADJ(ip)));
                        xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
                                (xfs_bmdr_block_t *)cp,
                                XFS_DFORK_SIZE(dip, mp, whichfork));
diff --git a/libxfs/xfs_mount.c b/libxfs/xfs_mount.c
index b7514fb..7ab3519 100644
--- a/libxfs/xfs_mount.c
+++ b/libxfs/xfs_mount.c
@@ -333,7 +333,7 @@ xfs_sb_verify(
         * Only check the in progress field for the primary superblock as
         * mkfs.xfs doesn't clear it from secondary superblocks.
         */
-       error = xfs_mount_validate_sb(mp, &sb, bp->b_blkno == XFS_SB_DADDR);
+       error = xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR);
        if (error)
                xfs_buf_ioerror(bp, error);
 }
diff --git a/mdrestore/Makefile b/mdrestore/Makefile
index ca2d1a0..5171306 100644
--- a/mdrestore/Makefile
+++ b/mdrestore/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
 LTCOMMAND = xfs_mdrestore
 CFILES = xfs_mdrestore.c
 
-LLDLIBS = $(LIBXFS) $(LIBRT) $(LIBPTHREAD)
+LLDLIBS = $(LIBXFS) $(LIBRT) $(LIBPTHREAD) $(LIBUUID)
 LTDEPENDENCIES = $(LIBXFS)
 LLDFLAGS = -static
 
-- 
1.7.10.4

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