[PATCH 06/13] xfs: add support for large btree blocks

Christoph Hellwig
2009-02-10T20:30:17Z

[-- Attachment #1: xfs-large-btree-blocks --]
[-- Type: text/plain, Size: 36929 bytes --]

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.

Signed-off-by: Christoph Hellwig <hch@lst.de>

Index: xfs/fs/xfs/xfs_btree.h
===================================================================
--- xfs.orig/fs/xfs/xfs_btree.h 2009-02-09 19:05:49.005068530 +0100
+++ xfs/fs/xfs/xfs_btree.h 2009-02-09 19:15:42.836068971 +0100
@@ -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: xfs/fs/xfs/xfs_bmap_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap_btree.c 2009-02-09 19:05:49.009069179 +0100
+++ xfs/fs/xfs/xfs_bmap_btree.c 2009-02-09 19:15:42.838069994 +0100
@@ -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);
@@ -441,10 +449,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);
@@ -886,6 +902,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: xfs/fs/xfs/xfs_bmap_btree.h
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap_btree.h 2009-02-09 19:05:49.013068710 +0100
+++ xfs/fs/xfs/xfs_bmap_btree.h 2009-02-09 19:15:42.838069994 +0100
@@ -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;
@@ -144,10 +145,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 *) \
@@ -194,12 +196,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: xfs/fs/xfs/xfs_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_btree.c 2009-02-09 19:05:49.018069067 +0100
+++ xfs/fs/xfs/xfs_btree.c 2009-02-09 19:15:42.842069176 +0100
@@ -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;
@@ -272,18 +331,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;
@@ -324,9 +393,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;
}

/*
@@ -420,6 +497,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
@@ -474,6 +575,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;
}

@@ -498,6 +602,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;
}

@@ -640,6 +747,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;
@@ -680,6 +789,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;
@@ -909,20 +1020,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]);
+ struct xfs_btree_block *new = XFS_BUF_TO_BLOCK(bp);
+
+ new->bb_magic = cpu_to_be32(xfs_btree_magic(cur));
new->bb_level = cpu_to_be16(level);
new->bb_numrecs = cpu_to_be16(numrecs);

if (cur->bc_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);
+ if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+ new->bb_u.l.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+ uuid_copy(&new->bb_u.l.bb_uuid,
+ &cur->bc_mp->m_sb.sb_uuid);
+ new->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);
+ if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
+ new->bb_u.s.bb_blkno = cpu_to_be64(XFS_BUF_ADDR(bp));
+ uuid_copy(&new->bb_u.s.bb_uuid,
+ &cur->bc_mp->m_sb.sb_uuid);
+ new->bb_u.s.bb_pad = 0;
+ }
}
}

@@ -1013,19 +1138,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;
}

@@ -1043,6 +1177,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;

@@ -1051,20 +1186,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;
}

/*
@@ -1250,31 +1396,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,
@@ -2237,7 +2408,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.
@@ -2546,7 +2717,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: xfs/fs/xfs/xfs_dinode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dinode.h 2009-02-09 19:15:37.179944489 +0100
+++ xfs/fs/xfs/xfs_dinode.h 2009-02-09 19:15:42.843068745 +0100
@@ -106,8 +106,8 @@ typedef enum xfs_dinode_fmt {
#define XFS_LITINO(version, mp) \
((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.
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2009-02-09 19:05:49.026068758 +0100
+++ xfs/fs/xfs/xfs_inode.c 2009-02-09 19:15:42.848068962 +0100
@@ -596,6 +596,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 */
@@ -604,7 +605,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);

/*
@@ -616,13 +617,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);
}

@@ -2247,7 +2247,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;
@@ -2261,9 +2261,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);
@@ -2271,7 +2271,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;
}
@@ -2286,7 +2286,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) {
@@ -2294,7 +2294,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;
@@ -2324,7 +2325,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;
}

@@ -2665,7 +2666,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: xfs/fs/xfs/xfs_attr_leaf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_attr_leaf.c 2009-02-09 19:15:37.185944554 +0100
+++ xfs/fs/xfs/xfs_attr_leaf.c 2009-02-09 19:15:42.850068937 +0100
@@ -174,7 +174,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: xfs/fs/xfs/xfs_bmap.c
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap.c 2009-02-09 19:15:37.192068867 +0100
+++ xfs/fs/xfs/xfs_bmap.c 2009-02-09 19:15:42.854098570 +0100
@@ -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);
@@ -3686,7 +3702,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);
@@ -4562,11 +4584,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: xfs/fs/xfs/xfs_alloc_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_alloc_btree.c 2009-02-09 19:05:49.038069167 +0100
+++ xfs/fs/xfs/xfs_alloc_btree.c 2009-02-09 19:15:42.855068736 +0100
@@ -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: xfs/fs/xfs/xfs_ialloc_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_ialloc_btree.c 2009-02-09 19:05:49.043068895 +0100
+++ xfs/fs/xfs/xfs_ialloc_btree.c 2009-02-09 19:15:42.857069060 +0100
@@ -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: xfs/fs/xfs/xfs_fsops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_fsops.c 2009-02-09 19:05:49.047068705 +0100
+++ xfs/fs/xfs/xfs_fsops.c 2009-02-09 19:15:42.860069581 +0100
@@ -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: xfs/fs/xfs/xfs_alloc_btree.h
===================================================================
--- xfs.orig/fs/xfs/xfs_alloc_btree.h 2009-02-09 19:05:49.051069843 +0100
+++ xfs/fs/xfs/xfs_alloc_btree.h 2009-02-09 19:15:42.862069766 +0100
@@ -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: xfs/fs/xfs/xfs_ialloc_btree.h
===================================================================
--- xfs.orig/fs/xfs/xfs_ialloc_btree.h 2009-02-09 19:05:49.055069304 +0100
+++ xfs/fs/xfs/xfs_ialloc_btree.h 2009-02-09 19:15:42.866069437 +0100
@@ -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))
@@ -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.
Index: xfs/fs/xfs/xfs_log_recover.c
===================================================================
--- xfs.orig/fs/xfs/xfs_log_recover.c 2009-02-09 19:15:38.648943978 +0100
+++ xfs/fs/xfs/xfs_log_recover.c 2009-02-09 19:15:42.873069001 +0100
@@ -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"
@@ -1980,6 +1981,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);