xfs
[Top] [All Lists]

[PATCH 5/9] add support for large btree blocks with CRCs and additional

To: xfs@xxxxxxxxxxx
Subject: [PATCH 5/9] add support for large btree blocks with CRCs and additional RAS information
From: Christoph Hellwig <hch@xxxxxx>
Date: Fri, 26 Sep 2008 00:56:33 +0200
User-agent: Mutt/1.3.28i
Add support for larger btree blocks that contains a CRC32C checksum, a
filesystem uuid and block number for detecting filesystem consistency
and out of place writes.  The use of these blocks is triggered by the
crc superblock patches just added.

Note that we currently do not log the crc of the block, but re-created
it during log recovery.  With the pending patch to also checksum the log
this should be safe against filesystem corruption but doesn't really
follow the end to end argument.  Also poking into the buffer to find
out whether this is a btree buffer during log recovery is not a very
clean way to implement this.  I'll look into how well adding crcs
to the buffer log items for every btree is going to work and hope
I can switch to that variant for the next version.


Signed-off-by: Christoph Hellwig <hch@xxxxxx>

Index: linux-2.6-xfs/fs/xfs/xfs_btree.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_btree.h       2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_btree.h    2008-09-25 20:10:37.000000000 +0200
@@ -47,6 +47,10 @@ extern kmem_zone_t   *xfs_btree_cur_zone;
  *
  * 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 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,32 @@ struct xfs_btree_block {
                struct {
                        __be32          bb_leftsib;
                        __be32          bb_rightsib;
+
+                       __be64          bb_blkno;
+                       uuid_t          bb_uuid;
+                       __be32          bb_crc;
+                       __be32          bb_pad; /* padding for alignment */
                } s;                    /* short form pointers */
                struct  {
                        __be64          bb_leftsib;
                        __be64          bb_rightsib;
+
+                       __be64          bb_blkno;
+                       uuid_t          bb_uuid;
+                       __be32          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 +121,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 +293,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
@@ -438,6 +457,12 @@ int xfs_btree_delete(struct xfs_btree_cu
 int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *);
 
 /*
+ * CRC calculation is also needed for growfs.
+ */
+void xfs_btree_lblock_calc_crc(struct xfs_buf *);
+void xfs_btree_sblock_calc_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);
Index: linux-2.6-xfs/fs/xfs/xfs_bmap_btree.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_bmap_btree.c  2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_bmap_btree.c       2008-09-25 20:10:37.000000000 
+0200
@@ -77,12 +77,20 @@ xfs_bmdr_to_bmbt(
        xfs_bmbt_key_t          *tkp;
        __be64                  *tpp;
 
-       rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
+       else
+               rblock->bb_magic = cpu_to_be32(XFS_BMAP_CRC_MAGIC);
        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);
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               rblock->bb_u.l.bb_blkno = cpu_to_be64(XFS_BUF_DADDR_NULL);
+               uuid_copy(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+               rblock->bb_u.l.bb_pad = 0;
+       }
        dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
        fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
        tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
@@ -440,10 +448,18 @@ xfs_bmbt_to_bmdr(
        xfs_bmbt_key_t          *tkp;
        __be64                  *tpp;
 
-       ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_MAGIC);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_CRC_MAGIC);
+       else
+               ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_MAGIC);
        ASSERT(be64_to_cpu(rblock->bb_u.l.bb_leftsib) == NULLDFSBNO);
        ASSERT(be64_to_cpu(rblock->bb_u.l.bb_rightsib) == NULLDFSBNO);
        ASSERT(be16_to_cpu(rblock->bb_level) > 0);
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               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));
+       }
        dblock->bb_level = rblock->bb_level;
        dblock->bb_numrecs = rblock->bb_numrecs;
        dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
@@ -885,6 +901,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;
Index: linux-2.6-xfs/fs/xfs/xfs_bmap_btree.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_bmap_btree.h  2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_bmap_btree.h       2008-09-25 20:10:37.000000000 
+0200
@@ -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     0x424d4158
 
 struct xfs_btree_cur;
 struct xfs_btree_block;
@@ -148,10 +149,11 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_
 
 /*
  * 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 *) \
@@ -198,12 +200,12 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_
 #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))))
Index: linux-2.6-xfs/fs/xfs/xfs_btree.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_btree.c       2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_btree.c    2008-09-25 20:10:37.000000000 +0200
@@ -39,6 +39,7 @@
 #include "xfs_btree_trace.h"
 #include "xfs_ialloc.h"
 #include "xfs_error.h"
+#include "xfs_cksum.h"
 
 /*
  * Cursor allocation zone.
@@ -48,9 +49,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) */
@@ -64,8 +69,34 @@ xfs_btree_check_lblock(
        struct xfs_mount        *mp;    /* file system mount point */
 
        mp = cur->bc_mp;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               /*
+                * Validate the CRC of the btree block only if the block is
+                * clean (i.e. it just came from disk) and we have CRCs enabled.
+                *
+                * If we are called for an in inode root block don't check the
+                * crc because we only calculate it for real btree blocks on
+                * disk.
+                */
+               if (bp && !(XFS_BUF_ISWRITE(bp) || XFS_BUF_ISDELAYWRITE(bp)) &&
+                   !xfs_verify_cksum(XFS_BUF_PTR(bp), XFS_BUF_SIZE(bp),
+                                     XFS_BTREE_LBLOCK_CRC_OFF)) {
+                       XFS_CORRUPTION_ERROR("xfs_btree_check_lblock crc",
+                               XFS_ERRLEVEL_LOW, mp, mp);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+
+               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 ? XFS_BUF_ADDR(bp) : XFS_BUF_DADDR_NULL);
+               if (!lblock_ok)
+                       goto test_error;
+       }
+
        lblock_ok =
-               be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] &&
+               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) &&
@@ -77,6 +108,8 @@ xfs_btree_check_lblock(
                (be64_to_cpu(block->bb_u.l.bb_rightsib) == NULLDFSBNO ||
                 XFS_FSB_SANITY_CHECK(mp,
                        be64_to_cpu(block->bb_u.l.bb_rightsib)));
+
+ test_error:
        if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp,
                        XFS_ERRTAG_BTREE_CHECK_LBLOCK,
                        XFS_RANDOM_BTREE_CHECK_LBLOCK))) {
@@ -96,16 +129,40 @@ 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 */
 
+       mp = cur->bc_mp;
        agbp = cur->bc_private.a.agbp;
        agf = XFS_BUF_TO_AGF(agbp);
        agflen = be32_to_cpu(agf->agf_length);
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               /*
+                * Validate the CRC of the btree block only if the block is
+                * clean (i.e. it just came from disk) and we have CRCs enabled.
+                */
+               if (!(XFS_BUF_ISWRITE(bp) || XFS_BUF_ISDELAYWRITE(bp)) &&
+                   !xfs_verify_cksum(XFS_BUF_PTR(bp), XFS_BUF_SIZE(bp),
+                                     XFS_BTREE_SBLOCK_CRC_OFF)) {
+                       XFS_CORRUPTION_ERROR("xfs_btree_check_sblock crc",
+                               XFS_ERRLEVEL_LOW, mp, mp);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+
+               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 ? XFS_BUF_ADDR(bp) : XFS_BUF_DADDR_NULL);
+               if (!sblock_ok)
+                       goto test_error;
+       }
+
        sblock_ok =
-               be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] &&
+               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) &&
@@ -115,13 +172,15 @@ xfs_btree_check_sblock(
                (be32_to_cpu(block->bb_u.s.bb_rightsib) == 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,
+
+ test_error:
+       if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp,
                        XFS_ERRTAG_BTREE_CHECK_SBLOCK,
                        XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
                if (bp)
                        xfs_buftrace("SBTREE ERROR", bp);
                XFS_ERROR_REPORT("xfs_btree_check_sblock", XFS_ERRLEVEL_LOW,
-                                cur->bc_mp);
+                                mp);
                return XFS_ERROR(EFSCORRUPTED);
        }
        return 0;
@@ -270,18 +329,28 @@ xfs_btree_dup_cursor(
        for (i = 0; i < new->bc_nlevels; i++) {
                new->bc_ptrs[i] = cur->bc_ptrs[i];
                new->bc_ra[i] = cur->bc_ra[i];
-               if ((bp = cur->bc_bufs[i])) {
-                       if ((error = xfs_trans_read_buf(mp, tp, 
mp->m_ddev_targp,
-                               XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) {
+               bp = cur->bc_bufs[i];
+               if (bp) {
+                       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
+                               XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp);
+                       if (error) {
                                xfs_btree_del_cursor(new, error);
                                *ncur = NULL;
                                return error;
                        }
-                       new->bc_bufs[i] = bp;
+
                        ASSERT(bp);
                        ASSERT(!XFS_BUF_GETERROR(bp));
-               } else
-                       new->bc_bufs[i] = NULL;
+
+                       if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+                               xfs_buf_set_io_callback(bp,
+                                       (cur->bc_flags & XFS_BTREE_LONG_PTRS) ?
+                                               xfs_btree_lblock_calc_crc :
+                                               xfs_btree_sblock_calc_crc);
+                       }
+
+               }
+               new->bc_bufs[i] = bp;
        }
        *ncur = new;
        return 0;
@@ -322,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;
 }
 
 /*
@@ -418,6 +495,30 @@ xfs_btree_ptr_addr(
 }
 
 /*
+ * Calculate CRC on the whole btree block and stuff it into the
+ * long-form btree header.
+ */
+void
+xfs_btree_lblock_calc_crc(
+       struct xfs_buf          *bp)
+{
+       xfs_update_cksum(XFS_BUF_PTR(bp), XFS_BUF_SIZE(bp),
+                        XFS_BTREE_LBLOCK_CRC_OFF);
+}
+
+/*
+ * Calculate CRC on the whole btree block and stuff it into the
+ * short-form btree header.
+ */
+void
+xfs_btree_sblock_calc_crc(
+       struct xfs_buf          *bp)
+{
+       xfs_update_cksum(XFS_BUF_PTR(bp), XFS_BUF_SIZE(bp),
+                        XFS_BTREE_SBLOCK_CRC_OFF);
+}
+
+/*
  * Get a the root block which is stored in the inode.
  *
  * For now this btree implementation assumes the btree root is always
@@ -472,6 +573,9 @@ xfs_btree_get_bufl(
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
        ASSERT(bp);
        ASSERT(!XFS_BUF_GETERROR(bp));
+
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               xfs_buf_set_io_callback(bp, xfs_btree_lblock_calc_crc);
        return bp;
 }
 
@@ -496,6 +600,9 @@ xfs_btree_get_bufs(
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
        ASSERT(bp);
        ASSERT(!XFS_BUF_GETERROR(bp));
+
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
        return bp;
 }
 
@@ -638,6 +745,8 @@ xfs_btree_read_bufl(
        ASSERT(!bp || !XFS_BUF_GETERROR(bp));
        if (bp != NULL) {
                XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
+               if (xfs_sb_version_hascrc(&mp->m_sb))
+                       xfs_buf_set_io_callback(bp, xfs_btree_lblock_calc_crc);
        }
        *bpp = bp;
        return 0;
@@ -678,6 +787,8 @@ xfs_btree_read_bufs(
                        XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval);
                        break;
                }
+               if (xfs_sb_version_hascrc(&mp->m_sb))
+                       xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
        }
        *bpp = bp;
        return 0;
@@ -907,20 +1018,34 @@ xfs_btree_set_sibling(
 STATIC void
 xfs_btree_init_block(
        struct xfs_btree_cur    *cur,
+       struct xfs_buf          *bp,
        int                     level,
-       int                     numrecs,
-       struct xfs_btree_block  *new)   /* new block */
+       int                     numrecs)
 {
-       new->bb_magic = cpu_to_be32(xfs_magics[cur->bc_btnum]);
-       new->bb_level = cpu_to_be16(level);
-       new->bb_numrecs = cpu_to_be16(numrecs);
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+
+       block->bb_magic = cpu_to_be32(xfs_btree_magic(cur));
+       block->bb_level = cpu_to_be16(level);
+       block->bb_numrecs = cpu_to_be16(numrecs);
 
        if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
-               new->bb_u.l.bb_leftsib = cpu_to_be64(NULLFSBLOCK);
-               new->bb_u.l.bb_rightsib = cpu_to_be64(NULLFSBLOCK);
+               block->bb_u.l.bb_leftsib = cpu_to_be64(NULLFSBLOCK);
+               block->bb_u.l.bb_rightsib = cpu_to_be64(NULLFSBLOCK);
+               if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+                       block->bb_u.l.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+                       uuid_copy(&block->bb_u.l.bb_uuid,
+                                 &cur->bc_mp->m_sb.sb_uuid);
+                       block->bb_u.l.bb_pad = 0;
+               }
        } else {
-               new->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
-               new->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
+               block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
+               block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
+               if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+                       block->bb_u.s.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+                       uuid_copy(&block->bb_u.s.bb_uuid,
+                                 &cur->bc_mp->m_sb.sb_uuid);
+                       block->bb_u.s.bb_pad = 0;
+               }
        }
 }
 
@@ -1011,19 +1136,28 @@ xfs_btree_get_buf_block(
        struct xfs_buf          **bpp)
 {
        struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_buf          *bp;
        xfs_daddr_t             d;
 
        /* need to sort out how callers deal with failures first */
        ASSERT(!(flags & XFS_BUF_TRYLOCK));
 
        d = xfs_btree_ptr_to_daddr(cur, ptr);
-       *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
-                                mp->m_bsize, flags);
+       bp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
+                              mp->m_bsize, flags);
 
-       ASSERT(*bpp);
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(bp);
+       ASSERT(!XFS_BUF_GETERROR(bp));
+
+       if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+               if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+                       xfs_buf_set_io_callback(bp, xfs_btree_lblock_calc_crc);
+               else
+                       xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
+       }
 
-       *block = XFS_BUF_TO_BLOCK(*bpp);
+       *block = XFS_BUF_TO_BLOCK(bp);
+       *bpp = bp;
        return 0;
 }
 
@@ -1041,6 +1175,7 @@ xfs_btree_read_buf_block(
        struct xfs_buf          **bpp)
 {
        struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_buf          *bp;
        xfs_daddr_t             d;
        int                     error;
 
@@ -1049,20 +1184,31 @@ xfs_btree_read_buf_block(
 
        d = xfs_btree_ptr_to_daddr(cur, ptr);
        error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
-                                  mp->m_bsize, flags, bpp);
+                                  mp->m_bsize, flags, &bp);
        if (error)
                return error;
 
-       ASSERT(*bpp != NULL);
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(bp != NULL);
+       ASSERT(!XFS_BUF_GETERROR(bp));
 
-       xfs_btree_set_refs(cur, *bpp);
-       *block = XFS_BUF_TO_BLOCK(*bpp);
+       xfs_btree_set_refs(cur, bp);
+       *block = XFS_BUF_TO_BLOCK(bp);
 
-       error = xfs_btree_check_block(cur, *block, level, *bpp);
-       if (error)
-               xfs_trans_brelse(cur->bc_tp, *bpp);
-       return error;
+       if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+               if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+                       xfs_buf_set_io_callback(bp, xfs_btree_lblock_calc_crc);
+               else
+                       xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
+       }
+
+       error = xfs_btree_check_block(cur, *block, level, bp);
+       if (error) {
+               xfs_trans_brelse(cur->bc_tp, bp);
+               return error;
+       }
+
+       *bpp = bp;
+       return 0;
 }
 
 /*
@@ -1248,31 +1394,56 @@ xfs_btree_log_block(
 {
        int                     first;  /* first byte offset logged */
        int                     last;   /* last byte offset logged */
-       static const short      soffsets[] = {  /* table of offsets (short) */
+       static const short      soffsets[] = {  /* short + crc */
                offsetof(struct xfs_btree_block, bb_magic),
                offsetof(struct xfs_btree_block, bb_level),
                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_crc),
+               offsetof(struct xfs_btree_block, bb_u.s.bb_uuid),
+               offsetof(struct xfs_btree_block, bb_u.s.bb_pad),
+               XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD
        };
-       static const short      loffsets[] = {  /* table of offsets (long) */
+       static const short      loffsets[] = {  /* long + crc */
                offsetof(struct xfs_btree_block, bb_magic),
                offsetof(struct xfs_btree_block, bb_level),
                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_crc),
+               offsetof(struct xfs_btree_block, bb_u.l.bb_uuid),
+               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);
+                                       loffsets : soffsets,
+                                 nbits, &first, &last);
                xfs_trans_log_buf(cur->bc_tp, bp, first, last);
        } else {
                xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
@@ -2235,7 +2406,7 @@ xfs_btree_split(
                goto error0;
 
        /* Fill in the btree header for the new right block. */
-       xfs_btree_init_block(cur, xfs_btree_get_level(left), 0, right);
+       xfs_btree_init_block(cur, rbp, xfs_btree_get_level(left), 0);
 
        /*
         * Split the entries between the old and the new block evenly.
@@ -2544,7 +2715,7 @@ xfs_btree_new_root(
                nptr = 2;
        }
        /* Fill in the new block's btree header and log it. */
-       xfs_btree_init_block(cur, cur->bc_nlevels, 2, new);
+       xfs_btree_init_block(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));
Index: linux-2.6-xfs/fs/xfs/xfs_dinode.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_dinode.h      2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_dinode.h   2008-09-25 20:10:37.000000000 +0200
@@ -164,8 +164,8 @@ typedef enum xfs_dinode_fmt
  * Inode size for given fs.
  */
 #define        XFS_LITINO(mp)  ((mp)->m_litino)
-#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.
Index: linux-2.6-xfs/fs/xfs/xfs_inode.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_inode.c       2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_inode.c    2008-09-25 20:10:37.000000000 +0200
@@ -613,6 +613,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 */
@@ -621,7 +622,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);
 
        /*
@@ -633,13 +634,12 @@ xfs_iformat_btree(
         */
        if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max
            || 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_fs_repair_cmn_err(CE_WARN, ip->i_mount,
+               xfs_fs_repair_cmn_err(CE_WARN, mp,
                        "corrupt inode %Lu (btree).",
                        (unsigned long long) ip->i_ino);
-               XFS_ERROR_REPORT("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
-                                ip->i_mount);
+               XFS_ERROR_REPORT("xfs_iformat_btree", XFS_ERRLEVEL_LOW, mp);
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -2330,7 +2330,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);
                        ifp->if_broot_bytes = (int)new_size;
                        return;
@@ -2344,9 +2344,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 = (size_t)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 */
+                               (size_t)XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max), 
/* old size */
                                KM_SLEEP);
                op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
                                                     ifp->if_broot_bytes);
@@ -2354,7 +2354,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;
        }
@@ -2369,7 +2369,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 = (size_t)XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
        else
                new_size = 0;
        if (new_size > 0) {
@@ -2377,7 +2377,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;
@@ -2407,7 +2408,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;
 }
 
@@ -2874,7 +2875,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));
Index: linux-2.6-xfs/fs/xfs/xfs_attr_leaf.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_attr_leaf.c   2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_attr_leaf.c        2008-09-25 20:10:37.000000000 
+0200
@@ -172,7 +172,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t 
                        else 
                                return dp->i_d.di_forkoff;
                } else
-                       dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
+                       dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
                break;
        }
        
Index: linux-2.6-xfs/fs/xfs/xfs_bmap.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_bmap.c        2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_bmap.c     2008-09-25 20:10:37.000000000 +0200
@@ -3465,6 +3465,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);
        ASSERT(ifp->if_ext_max ==
@@ -3479,16 +3480,23 @@ xfs_bmap_extents_to_btree(
         * Fill in the root.
         */
        block = ifp->if_broot;
-       block->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               block->bb_magic = cpu_to_be32(XFS_BMAP_CRC_MAGIC);
+       else
+               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)) {
+               block->bb_u.l.bb_blkno = cpu_to_be64(XFS_BUF_DADDR_NULL);
+               uuid_copy(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+               block->bb_u.l.bb_pad = 0;
+       }
 
        /*
         * 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;
@@ -3537,10 +3545,18 @@ xfs_bmap_extents_to_btree(
         * Fill in the child block.
         */
        ablock = XFS_BUF_TO_BLOCK(abp);
-       ablock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               ablock->bb_magic = cpu_to_be32(XFS_BMAP_CRC_MAGIC);
+       else
+               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)) {
+               ablock->bb_u.l.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(abp));
+               uuid_copy(&ablock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+               ablock->bb_u.l.bb_pad = 0;
+       }
        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++) {
@@ -3568,8 +3584,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);
@@ -3662,7 +3678,13 @@ xfs_bmap_local_to_extents(
                ASSERT(args.fsbno != NULLFSBLOCK);
                ASSERT(args.len == 1);
                *firstblock = args.fsbno;
-               bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
+
+               bp = xfs_trans_get_buf(args.tp, args.mp->m_ddev_targp,
+                                      XFS_FSB_TO_DADDR(args.mp, args.fsbno),
+                                      args.mp->m_bsize, 0);
+               ASSERT(bp);
+               ASSERT(!XFS_BUF_GETERROR(bp));
+
                memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
                        ifp->if_bytes);
                xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
@@ -4532,11 +4554,21 @@ xfs_bmap_sanity_check(
 {
        struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
 
-       if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC ||
-           be16_to_cpu(block->bb_level) != level ||
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               if (be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC ||
+                   !uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) ||
+                   block->bb_u.l.bb_blkno != cpu_to_be64(XFS_BUF_ADDR(bp)))
+                       return 0;
+       } else {
+               if (be32_to_cpu(block->bb_magic) != 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;
 }
 
Index: linux-2.6-xfs/fs/xfs/xfs_alloc_btree.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_alloc_btree.c 2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_alloc_btree.c      2008-09-25 20:10:37.000000000 
+0200
@@ -474,6 +474,8 @@ xfs_allocbt_init_cursor(
        cur->bc_ops = &xfs_allocbt_ops;
        if (btnum == XFS_BTNUM_CNT)
                cur->bc_flags = XFS_BTREE_LASTREC_UPDATE;
+       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;
Index: linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_ialloc_btree.c        2008-09-25 
20:05:07.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.c     2008-09-25 20:10:37.000000000 
+0200
@@ -359,6 +359,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;
Index: linux-2.6-xfs/fs/xfs/xfs_mount.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_mount.c       2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_mount.c    2008-09-26 00:34:28.000000000 +0200
@@ -567,6 +567,12 @@ xfs_readsb(xfs_mount_t *mp, int flags)
 STATIC void
 xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
 {
+
+       if (xfs_sb_version_hascrc(sbp))
+               printk("XFS: using CRCs\n");
+       else
+               printk("XFS: not using CRCs\n");
+
        mp->m_agfrotor = mp->m_agirotor = 0;
        spin_lock_init(&mp->m_agirotor_lock);
        mp->m_maxagi = mp->m_sb.sb_agcount;
Index: linux-2.6-xfs/fs/xfs/xfs_fsops.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_fsops.c       2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_fsops.c    2008-09-26 00:34:27.000000000 +0200
@@ -253,11 +253,19 @@ xfs_growfs_data_private(
                        BTOBB(mp->m_sb.sb_blocksize), 0);
                block = XFS_BUF_TO_BLOCK(bp);
                memset(block, 0, mp->m_sb.sb_blocksize);
-               block->bb_magic = cpu_to_be32(XFS_ABTB_MAGIC);
                block->bb_level = 0;
                block->bb_numrecs = cpu_to_be16(1);
                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
+               if (xfs_sb_version_hascrc(&mp->m_sb)) {
+                       block->bb_magic = cpu_to_be32(XFS_ABTB_CRC_MAGIC);
+                       block->bb_u.s.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+                       uuid_copy(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+                       block->bb_u.s.bb_pad = 0;
+                       xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
+               } else {
+                       block->bb_magic = cpu_to_be32(XFS_ABTB_MAGIC);
+               }
                arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
                arec->ar_blockcount = cpu_to_be32(
@@ -274,11 +282,19 @@ xfs_growfs_data_private(
                        BTOBB(mp->m_sb.sb_blocksize), 0);
                block = XFS_BUF_TO_BLOCK(bp);
                memset(block, 0, mp->m_sb.sb_blocksize);
-               block->bb_magic = cpu_to_be32(XFS_ABTC_MAGIC);
                block->bb_level = 0;
                block->bb_numrecs = cpu_to_be16(1);
                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
+               if (xfs_sb_version_hascrc(&mp->m_sb)) {
+                       block->bb_magic = cpu_to_be32(XFS_ABTC_CRC_MAGIC);
+                       block->bb_u.s.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+                       uuid_copy(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+                       block->bb_u.s.bb_pad = 0;
+                       xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
+               } else {
+                       block->bb_magic = cpu_to_be32(XFS_ABTC_MAGIC);
+               }
                arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
                arec->ar_blockcount = cpu_to_be32(
@@ -296,11 +312,19 @@ xfs_growfs_data_private(
                        BTOBB(mp->m_sb.sb_blocksize), 0);
                block = XFS_BUF_TO_BLOCK(bp);
                memset(block, 0, mp->m_sb.sb_blocksize);
-               block->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
                block->bb_level = 0;
                block->bb_numrecs = 0;
                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
+               if (xfs_sb_version_hascrc(&mp->m_sb)) {
+                       block->bb_magic = cpu_to_be32(XFS_IBT_CRC_MAGIC);
+                       block->bb_u.s.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+                       uuid_copy(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+                       block->bb_u.s.bb_pad = 0;
+                       xfs_buf_set_io_callback(bp, xfs_btree_sblock_calc_crc);
+               } else {
+                       block->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
+               }
                error = xfs_bwrite(mp, bp);
                if (error) {
                        goto error0;
Index: linux-2.6-xfs/fs/xfs/xfs_alloc_btree.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_alloc_btree.h 2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_alloc_btree.h      2008-09-25 20:10:37.000000000 
+0200
@@ -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      0x4142544a
+#define        XFS_ABTC_MAGIC          0x41425443      /* 'ABTC' for cnt tree 
*/
+#define        XFS_ABTC_CRC_MAGIC      0x4142544b
 
 /*
  * Data record/key structure
@@ -73,10 +75,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.
Index: linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.h
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_ialloc_btree.h        2008-09-25 
20:05:07.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.h     2008-09-25 20:10:37.000000000 
+0200
@@ -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       0x4941425c
 
 typedef        __uint64_t      xfs_inofree_t;
 #define        XFS_INODES_PER_CHUNK    (NBBY * sizeof(xfs_inofree_t))
@@ -91,10 +92,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.
Index: linux-2.6-xfs/fs/xfs/xfs_log_recover.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfs_log_recover.c 2008-09-25 20:05:07.000000000 
+0200
+++ linux-2.6-xfs/fs/xfs/xfs_log_recover.c      2008-09-26 00:35:04.000000000 
+0200
@@ -31,6 +31,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -1931,6 +1932,19 @@ xlog_recover_do_reg_buffer(
                bit += nbits;
        }
 
+       switch (be32_to_cpu(*(__be32 *)XFS_BUF_PTR(bp))) {
+       case XFS_ABTB_CRC_MAGIC:
+       case XFS_ABTC_CRC_MAGIC:
+       case XFS_IBT_CRC_MAGIC:
+               xfs_btree_sblock_calc_crc(bp);
+               break;
+       case XFS_BMAP_CRC_MAGIC:
+               xfs_btree_lblock_calc_crc(bp);
+               break;
+       default:
+               break;
+       }
+
        /* Shouldn't be any more regions */
        ASSERT(i == item->ri_total);
 }
Index: linux-2.6-xfs/fs/xfs/xfsidbg.c
===================================================================
--- linux-2.6-xfs.orig/fs/xfs/xfsidbg.c 2008-09-25 20:05:07.000000000 +0200
+++ linux-2.6-xfs/fs/xfs/xfsidbg.c      2008-09-25 20:10:37.000000000 +0200
@@ -3060,6 +3060,26 @@ xfsidbg_print_btree_lblock(struct xfs_bt
 }
 
 static void
+xfsidbg_print_btree_sblock_crc(struct xfs_btree_block *block)
+{
+       xfsidbg_print_btree_sblock(block);
+       kdb_printf("blkno 0x%llx uuid %s crc %d\n",
+                       (unsigned long long)be64_to_cpu(block->bb_u.s.bb_blkno),
+                       xfs_fmtuuid(&block->bb_u.s.bb_uuid),
+                       be32_to_cpu(block->bb_u.s.bb_crc));
+}
+
+static void
+xfsidbg_print_btree_lblock_crc(struct xfs_btree_block *block)
+{
+       xfsidbg_print_btree_lblock(block);
+       kdb_printf("blkno 0x%llx uuid %s crc %d\n",
+                       (unsigned long long)be64_to_cpu(block->bb_u.l.bb_blkno),
+                       xfs_fmtuuid(&block->bb_u.l.bb_uuid),
+                       be32_to_cpu(block->bb_u.l.bb_crc));
+}
+
+static void
 xfsidbg_print_alloc_rec(int i, union xfs_btree_rec *rec)
 {
        kdb_printf("rec %d startblock 0x%x blockcount %d\n", i,
@@ -3087,6 +3107,16 @@ static struct xfsidbg_btree xfsidbg_allo
        .print_key      = xfsidbg_print_alloc_key,
 };
 
+static struct xfsidbg_btree xfsidbg_allocbtcrc = {
+       .block_len      = XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD,
+       .key_len        = sizeof(xfs_alloc_key_t),
+       .rec_len        = sizeof(xfs_alloc_rec_t),
+       .ptr_len        = sizeof(__be32),
+       .print_block    = xfsidbg_print_btree_sblock_crc,
+       .print_rec      = xfsidbg_print_alloc_rec,
+       .print_key      = xfsidbg_print_alloc_key,
+};
+
 static void
 xfsidbg_print_bmbt_rec(int i, union xfs_btree_rec *rec)
 {
@@ -3119,6 +3149,16 @@ static struct xfsidbg_btree xfsidbg_bmbt
        .print_key      = xfsidbg_print_bmbt_key,
 };
 
+static struct xfsidbg_btree xfsidbg_bmbtcrc = {
+       .block_len      = XFS_BTREE_LBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD,
+       .key_len        = sizeof(xfs_bmbt_key_t),
+       .rec_len        = sizeof(xfs_bmbt_rec_t),
+       .ptr_len        = sizeof(__be64),
+       .print_block    = xfsidbg_print_btree_lblock_crc,
+       .print_rec      = xfsidbg_print_bmbt_rec,
+       .print_key      = xfsidbg_print_bmbt_key,
+};
+
 static void
 xfsidbg_print_inobt_rec(int i, union xfs_btree_rec *rec)
 {
@@ -3147,6 +3187,16 @@ static struct xfsidbg_btree xfsidbg_inob
        .print_key      = xfsidbg_print_inobt_key,
 };
 
+static struct xfsidbg_btree xfsidbg_inobtbtcrc = {
+       .block_len      = XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD,
+       .key_len        = sizeof(xfs_inobt_key_t),
+       .rec_len        = sizeof(xfs_inobt_rec_t),
+       .ptr_len        = sizeof(__be32),
+       .print_block    = xfsidbg_print_btree_sblock_crc,
+       .print_rec      = xfsidbg_print_inobt_rec,
+       .print_key      = xfsidbg_print_inobt_key,
+};
+
 /*
  * Print an xfs in-inode bmap btree root.
  */
@@ -4830,6 +4880,38 @@ xfsidbg_xbuf_real(xfs_buf_t *bp, int sum
                        kdb_printf("buf 0x%p inobt 0x%p\n", bp, bt);
                        xfs_btblock(bt, XFS_BUF_COUNT(bp), &xfsidbg_inobtbt);
                }
+       } else if (be32_to_cpu((bt = d)->bb_magic) == XFS_ABTB_CRC_MAGIC) {
+               if (summary) {
+                       kdb_printf("Alloc BNO Btree blk, level %d (at 0x%p)\n",
+                                      be16_to_cpu(bt->bb_level), bt);
+               } else {
+                       kdb_printf("buf 0x%p abtbno 0x%p\n", bp, bt);
+                       xfs_btblock(bt, XFS_BUF_COUNT(bp), &xfsidbg_allocbtcrc);
+               }
+       } else if (be32_to_cpu((bt = d)->bb_magic) == XFS_ABTC_CRC_MAGIC) {
+               if (summary) {
+                       kdb_printf("Alloc COUNT Btree blk, level %d (at 
0x%p)\n",
+                                      be16_to_cpu(bt->bb_level), bt);
+               } else {
+                       kdb_printf("buf 0x%p abtcnt 0x%p\n", bp, bt);
+                       xfs_btblock(bt, XFS_BUF_COUNT(bp), &xfsidbg_allocbtcrc);
+               }
+       } else if (be32_to_cpu((bt = d)->bb_magic) == XFS_BMAP_CRC_MAGIC) {
+               if (summary) {
+                       kdb_printf("Bmap Btree blk, level %d (at 0x%p)\n",
+                                     be16_to_cpu(bt->bb_level), bt);
+               } else {
+                       kdb_printf("buf 0x%p bmapbt 0x%p\n", bp, bt);
+                       xfs_btblock(bt, XFS_BUF_COUNT(bp), &xfsidbg_bmbtcrc);
+               }
+       } else if (be32_to_cpu((bt = d)->bb_magic) == XFS_IBT_CRC_MAGIC) {
+               if (summary) {
+                       kdb_printf("Inode Btree blk, level %d (at 0x%p)\n",
+                                      be16_to_cpu(bt->bb_level), bt);
+               } else {
+                       kdb_printf("buf 0x%p inobt 0x%p\n", bp, bt);
+                       xfs_btblock(bt, XFS_BUF_COUNT(bp), &xfsidbg_inobtbtcrc);
+               }
        } else if (be16_to_cpu((aleaf = d)->hdr.info.magic) == 
XFS_ATTR_LEAF_MAGIC) {
                if (summary) {
                        kdb_printf("Attr Leaf, 1st hash 0x%x (at 0x%p)\n",

-- 

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH 5/9] add support for large btree blocks with CRCs and additional RAS information, Christoph Hellwig <=