aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_alloc_btree.c105
-rw-r--r--fs/xfs/xfs_alloc_btree.h12
-rw-r--r--fs/xfs/xfs_attr_leaf.c2
-rw-r--r--fs/xfs/xfs_bmap.c47
-rw-r--r--fs/xfs/xfs_bmap_btree.c110
-rw-r--r--fs/xfs/xfs_bmap_btree.h19
-rw-r--r--fs/xfs/xfs_btree.c256
-rw-r--r--fs/xfs/xfs_btree.h64
-rw-r--r--fs/xfs/xfs_buf_item.h24
-rw-r--r--fs/xfs/xfs_dinode.h4
-rw-r--r--fs/xfs/xfs_fsops.c23
-rw-r--r--fs/xfs/xfs_ialloc_btree.c87
-rw-r--r--fs/xfs/xfs_ialloc_btree.h9
-rw-r--r--fs/xfs/xfs_inode.c33
-rw-r--r--fs/xfs/xfs_log_recover.c28
-rw-r--r--fs/xfs/xfs_trans.h2
-rw-r--r--fs/xfs/xfs_trans_buf.c29
17 files changed, 645 insertions, 209 deletions
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index b1ddef6b2689..30c4c1434faf 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -33,6 +33,7 @@
33#include "xfs_extent_busy.h" 33#include "xfs_extent_busy.h"
34#include "xfs_error.h" 34#include "xfs_error.h"
35#include "xfs_trace.h" 35#include "xfs_trace.h"
36#include "xfs_cksum.h"
36 37
37 38
38STATIC struct xfs_btree_cur * 39STATIC struct xfs_btree_cur *
@@ -272,7 +273,7 @@ xfs_allocbt_key_diff(
272 return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; 273 return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
273} 274}
274 275
275static void 276static bool
276xfs_allocbt_verify( 277xfs_allocbt_verify(
277 struct xfs_buf *bp) 278 struct xfs_buf *bp)
278{ 279{
@@ -280,66 +281,103 @@ xfs_allocbt_verify(
280 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 281 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
281 struct xfs_perag *pag = bp->b_pag; 282 struct xfs_perag *pag = bp->b_pag;
282 unsigned int level; 283 unsigned int level;
283 int sblock_ok; /* block passes checks */
284 284
285 /* 285 /*
286 * magic number and level verification 286 * magic number and level verification
287 * 287 *
288 * During growfs operations, we can't verify the exact level as the 288 * During growfs operations, we can't verify the exact level or owner as
289 * perag is not fully initialised and hence not attached to the buffer. 289 * the perag is not fully initialised and hence not attached to the
290 * In this case, check against the maximum tree depth. 290 * buffer. In this case, check against the maximum tree depth.
291 *
292 * Similarly, during log recovery we will have a perag structure
293 * attached, but the agf information will not yet have been initialised
294 * from the on disk AGF. Again, we can only check against maximum limits
295 * in this case.
291 */ 296 */
292 level = be16_to_cpu(block->bb_level); 297 level = be16_to_cpu(block->bb_level);
293 switch (block->bb_magic) { 298 switch (block->bb_magic) {
299 case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
300 if (!xfs_sb_version_hascrc(&mp->m_sb))
301 return false;
302 if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
303 return false;
304 if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
305 return false;
306 if (pag &&
307 be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
308 return false;
309 /* fall through */
294 case cpu_to_be32(XFS_ABTB_MAGIC): 310 case cpu_to_be32(XFS_ABTB_MAGIC):
295 if (pag) 311 if (pag && pag->pagf_init) {
296 sblock_ok = level < pag->pagf_levels[XFS_BTNUM_BNOi]; 312 if (level >= pag->pagf_levels[XFS_BTNUM_BNOi])
297 else 313 return false;
298 sblock_ok = level < mp->m_ag_maxlevels; 314 } else if (level >= mp->m_ag_maxlevels)
315 return false;
299 break; 316 break;
317 case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
318 if (!xfs_sb_version_hascrc(&mp->m_sb))
319 return false;
320 if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
321 return false;
322 if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
323 return false;
324 if (pag &&
325 be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
326 return false;
327 /* fall through */
300 case cpu_to_be32(XFS_ABTC_MAGIC): 328 case cpu_to_be32(XFS_ABTC_MAGIC):
301 if (pag) 329 if (pag && pag->pagf_init) {
302 sblock_ok = level < pag->pagf_levels[XFS_BTNUM_CNTi]; 330 if (level >= pag->pagf_levels[XFS_BTNUM_CNTi])
303 else 331 return false;
304 sblock_ok = level < mp->m_ag_maxlevels; 332 } else if (level >= mp->m_ag_maxlevels)
333 return false;
305 break; 334 break;
306 default: 335 default:
307 sblock_ok = 0; 336 return false;
308 break;
309 } 337 }
310 338
311 /* numrecs verification */ 339 /* numrecs verification */
312 sblock_ok = sblock_ok && 340 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[level != 0])
313 be16_to_cpu(block->bb_numrecs) <= mp->m_alloc_mxr[level != 0]; 341 return false;
314 342
315 /* sibling pointer verification */ 343 /* sibling pointer verification */
316 sblock_ok = sblock_ok && 344 if (!block->bb_u.s.bb_leftsib ||
317 (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || 345 (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
318 be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) && 346 block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
319 block->bb_u.s.bb_leftsib && 347 return false;
320 (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || 348 if (!block->bb_u.s.bb_rightsib ||
321 be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) && 349 (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
322 block->bb_u.s.bb_rightsib; 350 block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
323 351 return false;
324 if (!sblock_ok) { 352
325 trace_xfs_btree_corrupt(bp, _RET_IP_); 353 return true;
326 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
327 xfs_buf_ioerror(bp, EFSCORRUPTED);
328 }
329} 354}
330 355
331static void 356static void
332xfs_allocbt_read_verify( 357xfs_allocbt_read_verify(
333 struct xfs_buf *bp) 358 struct xfs_buf *bp)
334{ 359{
335 xfs_allocbt_verify(bp); 360 if (!(xfs_btree_sblock_verify_crc(bp) &&
361 xfs_allocbt_verify(bp))) {
362 trace_xfs_btree_corrupt(bp, _RET_IP_);
363 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
364 bp->b_target->bt_mount, bp->b_addr);
365 xfs_buf_ioerror(bp, EFSCORRUPTED);
366 }
336} 367}
337 368
338static void 369static void
339xfs_allocbt_write_verify( 370xfs_allocbt_write_verify(
340 struct xfs_buf *bp) 371 struct xfs_buf *bp)
341{ 372{
342 xfs_allocbt_verify(bp); 373 if (!xfs_allocbt_verify(bp)) {
374 trace_xfs_btree_corrupt(bp, _RET_IP_);
375 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
376 bp->b_target->bt_mount, bp->b_addr);
377 xfs_buf_ioerror(bp, EFSCORRUPTED);
378 }
379 xfs_btree_sblock_calc_crc(bp);
380
343} 381}
344 382
345const struct xfs_buf_ops xfs_allocbt_buf_ops = { 383const struct xfs_buf_ops xfs_allocbt_buf_ops = {
@@ -444,6 +482,9 @@ xfs_allocbt_init_cursor(
444 cur->bc_private.a.agbp = agbp; 482 cur->bc_private.a.agbp = agbp;
445 cur->bc_private.a.agno = agno; 483 cur->bc_private.a.agno = agno;
446 484
485 if (xfs_sb_version_hascrc(&mp->m_sb))
486 cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
487
447 return cur; 488 return cur;
448} 489}
449 490
diff --git a/fs/xfs/xfs_alloc_btree.h b/fs/xfs/xfs_alloc_btree.h
index 7e89a2b429dd..e3a3f7424192 100644
--- a/fs/xfs/xfs_alloc_btree.h
+++ b/fs/xfs/xfs_alloc_btree.h
@@ -31,8 +31,10 @@ struct xfs_mount;
31 * by blockcount and blockno. All blocks look the same to make the code 31 * by blockcount and blockno. All blocks look the same to make the code
32 * simpler; if we have time later, we'll make the optimizations. 32 * simpler; if we have time later, we'll make the optimizations.
33 */ 33 */
34#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ 34#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */
35#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ 35#define XFS_ABTB_CRC_MAGIC 0x41423342 /* 'AB3B' */
36#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */
37#define XFS_ABTC_CRC_MAGIC 0x41423343 /* 'AB3C' */
36 38
37/* 39/*
38 * Data record/key structure 40 * Data record/key structure
@@ -59,10 +61,10 @@ typedef __be32 xfs_alloc_ptr_t;
59 61
60/* 62/*
61 * Btree block header size depends on a superblock flag. 63 * Btree block header size depends on a superblock flag.
62 *
63 * (not quite yet, but soon)
64 */ 64 */
65#define XFS_ALLOC_BLOCK_LEN(mp) XFS_BTREE_SBLOCK_LEN 65#define XFS_ALLOC_BLOCK_LEN(mp) \
66 (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
67 XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN)
66 68
67/* 69/*
68 * Record, key, and pointer address macros for btree blocks. 70 * Record, key, and pointer address macros for btree blocks.
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index f96a734ed1e0..aa4765f15cbe 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -232,7 +232,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
232 return 0; 232 return 0;
233 return dp->i_d.di_forkoff; 233 return dp->i_d.di_forkoff;
234 } 234 }
235 dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot); 235 dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
236 break; 236 break;
237 } 237 }
238 238
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 20efb397a7f4..0531cd3927a9 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -439,11 +439,15 @@ xfs_bmap_sanity_check(
439{ 439{
440 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 440 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
441 441
442 if (block->bb_magic != cpu_to_be32(XFS_BMAP_MAGIC) || 442 if (block->bb_magic != cpu_to_be32(XFS_BMAP_CRC_MAGIC) &&
443 be16_to_cpu(block->bb_level) != level || 443 block->bb_magic != cpu_to_be32(XFS_BMAP_MAGIC))
444 return 0;
445
446 if (be16_to_cpu(block->bb_level) != level ||
444 be16_to_cpu(block->bb_numrecs) == 0 || 447 be16_to_cpu(block->bb_numrecs) == 0 ||
445 be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0]) 448 be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0])
446 return 0; 449 return 0;
450
447 return 1; 451 return 1;
448} 452}
449 453
@@ -1031,6 +1035,7 @@ xfs_bmap_extents_to_btree(
1031 xfs_extnum_t nextents; /* number of file extents */ 1035 xfs_extnum_t nextents; /* number of file extents */
1032 xfs_bmbt_ptr_t *pp; /* root block address pointer */ 1036 xfs_bmbt_ptr_t *pp; /* root block address pointer */
1033 1037
1038 mp = ip->i_mount;
1034 ifp = XFS_IFORK_PTR(ip, whichfork); 1039 ifp = XFS_IFORK_PTR(ip, whichfork);
1035 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); 1040 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS);
1036 1041
@@ -1044,16 +1049,18 @@ xfs_bmap_extents_to_btree(
1044 * Fill in the root. 1049 * Fill in the root.
1045 */ 1050 */
1046 block = ifp->if_broot; 1051 block = ifp->if_broot;
1047 block->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC); 1052 if (xfs_sb_version_hascrc(&mp->m_sb))
1048 block->bb_level = cpu_to_be16(1); 1053 xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL,
1049 block->bb_numrecs = cpu_to_be16(1); 1054 XFS_BMAP_CRC_MAGIC, 1, 1, ip->i_ino,
1050 block->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO); 1055 XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS);
1051 block->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO); 1056 else
1057 xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL,
1058 XFS_BMAP_MAGIC, 1, 1, ip->i_ino,
1059 XFS_BTREE_LONG_PTRS);
1052 1060
1053 /* 1061 /*
1054 * Need a cursor. Can't allocate until bb_level is filled in. 1062 * Need a cursor. Can't allocate until bb_level is filled in.
1055 */ 1063 */
1056 mp = ip->i_mount;
1057 cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); 1064 cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
1058 cur->bc_private.b.firstblock = *firstblock; 1065 cur->bc_private.b.firstblock = *firstblock;
1059 cur->bc_private.b.flist = flist; 1066 cur->bc_private.b.flist = flist;
@@ -1102,10 +1109,15 @@ xfs_bmap_extents_to_btree(
1102 */ 1109 */
1103 abp->b_ops = &xfs_bmbt_buf_ops; 1110 abp->b_ops = &xfs_bmbt_buf_ops;
1104 ablock = XFS_BUF_TO_BLOCK(abp); 1111 ablock = XFS_BUF_TO_BLOCK(abp);
1105 ablock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC); 1112 if (xfs_sb_version_hascrc(&mp->m_sb))
1106 ablock->bb_level = 0; 1113 xfs_btree_init_block_int(mp, ablock, abp->b_bn,
1107 ablock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO); 1114 XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino,
1108 ablock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO); 1115 XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS);
1116 else
1117 xfs_btree_init_block_int(mp, ablock, abp->b_bn,
1118 XFS_BMAP_MAGIC, 0, 0, ip->i_ino,
1119 XFS_BTREE_LONG_PTRS);
1120
1109 arp = XFS_BMBT_REC_ADDR(mp, ablock, 1); 1121 arp = XFS_BMBT_REC_ADDR(mp, ablock, 1);
1110 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); 1122 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1111 for (cnt = i = 0; i < nextents; i++) { 1123 for (cnt = i = 0; i < nextents; i++) {
@@ -1155,7 +1167,8 @@ xfs_bmap_local_to_extents(
1155 xfs_extlen_t total, /* total blocks needed by transaction */ 1167 xfs_extlen_t total, /* total blocks needed by transaction */
1156 int *logflagsp, /* inode logging flags */ 1168 int *logflagsp, /* inode logging flags */
1157 int whichfork, 1169 int whichfork,
1158 void (*init_fn)(struct xfs_buf *bp, 1170 void (*init_fn)(struct xfs_trans *tp,
1171 struct xfs_buf *bp,
1159 struct xfs_inode *ip, 1172 struct xfs_inode *ip,
1160 struct xfs_ifork *ifp)) 1173 struct xfs_ifork *ifp))
1161{ 1174{
@@ -1207,7 +1220,7 @@ xfs_bmap_local_to_extents(
1207 bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); 1220 bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
1208 1221
1209 /* initialise the block and copy the data */ 1222 /* initialise the block and copy the data */
1210 init_fn(bp, ip, ifp); 1223 init_fn(tp, bp, ip, ifp);
1211 1224
1212 /* account for the change in fork size and log everything */ 1225 /* account for the change in fork size and log everything */
1213 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); 1226 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
@@ -1314,16 +1327,19 @@ xfs_bmap_add_attrfork_extents(
1314 */ 1327 */
1315STATIC void 1328STATIC void
1316xfs_bmap_local_to_extents_init_fn( 1329xfs_bmap_local_to_extents_init_fn(
1330 struct xfs_trans *tp,
1317 struct xfs_buf *bp, 1331 struct xfs_buf *bp,
1318 struct xfs_inode *ip, 1332 struct xfs_inode *ip,
1319 struct xfs_ifork *ifp) 1333 struct xfs_ifork *ifp)
1320{ 1334{
1321 bp->b_ops = &xfs_bmbt_buf_ops; 1335 bp->b_ops = &xfs_bmbt_buf_ops;
1322 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); 1336 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
1337 xfs_trans_buf_set_type(tp, bp, XFS_BLF_BTREE_BUF);
1323} 1338}
1324 1339
1325STATIC void 1340STATIC void
1326xfs_symlink_local_to_remote( 1341xfs_symlink_local_to_remote(
1342 struct xfs_trans *tp,
1327 struct xfs_buf *bp, 1343 struct xfs_buf *bp,
1328 struct xfs_inode *ip, 1344 struct xfs_inode *ip,
1329 struct xfs_ifork *ifp) 1345 struct xfs_ifork *ifp)
@@ -1342,8 +1358,7 @@ xfs_symlink_local_to_remote(
1342 * 1358 *
1343 * XXX (dgc): investigate whether directory conversion can use the generic 1359 * XXX (dgc): investigate whether directory conversion can use the generic
1344 * formatting callout. It should be possible - it's just a very complex 1360 * formatting callout. It should be possible - it's just a very complex
1345 * formatter. it would also require passing the transaction through to the init 1361 * formatter.
1346 * function.
1347 */ 1362 */
1348STATIC int /* error */ 1363STATIC int /* error */
1349xfs_bmap_add_attrfork_local( 1364xfs_bmap_add_attrfork_local(
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 061b45cbe614..3a86c3fa6de1 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -37,6 +37,7 @@
37#include "xfs_error.h" 37#include "xfs_error.h"
38#include "xfs_quota.h" 38#include "xfs_quota.h"
39#include "xfs_trace.h" 39#include "xfs_trace.h"
40#include "xfs_cksum.h"
40 41
41/* 42/*
42 * Determine the extent state. 43 * Determine the extent state.
@@ -59,24 +60,31 @@ xfs_extent_state(
59 */ 60 */
60void 61void
61xfs_bmdr_to_bmbt( 62xfs_bmdr_to_bmbt(
62 struct xfs_mount *mp, 63 struct xfs_inode *ip,
63 xfs_bmdr_block_t *dblock, 64 xfs_bmdr_block_t *dblock,
64 int dblocklen, 65 int dblocklen,
65 struct xfs_btree_block *rblock, 66 struct xfs_btree_block *rblock,
66 int rblocklen) 67 int rblocklen)
67{ 68{
69 struct xfs_mount *mp = ip->i_mount;
68 int dmxr; 70 int dmxr;
69 xfs_bmbt_key_t *fkp; 71 xfs_bmbt_key_t *fkp;
70 __be64 *fpp; 72 __be64 *fpp;
71 xfs_bmbt_key_t *tkp; 73 xfs_bmbt_key_t *tkp;
72 __be64 *tpp; 74 __be64 *tpp;
73 75
74 rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC); 76 if (xfs_sb_version_hascrc(&mp->m_sb))
77 xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL,
78 XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino,
79 XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS);
80 else
81 xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL,
82 XFS_BMAP_MAGIC, 0, 0, ip->i_ino,
83 XFS_BTREE_LONG_PTRS);
84
75 rblock->bb_level = dblock->bb_level; 85 rblock->bb_level = dblock->bb_level;
76 ASSERT(be16_to_cpu(rblock->bb_level) > 0); 86 ASSERT(be16_to_cpu(rblock->bb_level) > 0);
77 rblock->bb_numrecs = dblock->bb_numrecs; 87 rblock->bb_numrecs = dblock->bb_numrecs;
78 rblock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
79 rblock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
80 dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); 88 dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
81 fkp = XFS_BMDR_KEY_ADDR(dblock, 1); 89 fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
82 tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); 90 tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
@@ -424,7 +432,13 @@ xfs_bmbt_to_bmdr(
424 xfs_bmbt_key_t *tkp; 432 xfs_bmbt_key_t *tkp;
425 __be64 *tpp; 433 __be64 *tpp;
426 434
427 ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); 435 if (xfs_sb_version_hascrc(&mp->m_sb)) {
436 ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
437 ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
438 ASSERT(rblock->bb_u.l.bb_blkno ==
439 cpu_to_be64(XFS_BUF_DADDR_NULL));
440 } else
441 ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC));
428 ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO)); 442 ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO));
429 ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO)); 443 ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO));
430 ASSERT(rblock->bb_level != 0); 444 ASSERT(rblock->bb_level != 0);
@@ -708,59 +722,89 @@ xfs_bmbt_key_diff(
708 cur->bc_rec.b.br_startoff; 722 cur->bc_rec.b.br_startoff;
709} 723}
710 724
711static void 725static int
712xfs_bmbt_verify( 726xfs_bmbt_verify(
713 struct xfs_buf *bp) 727 struct xfs_buf *bp)
714{ 728{
715 struct xfs_mount *mp = bp->b_target->bt_mount; 729 struct xfs_mount *mp = bp->b_target->bt_mount;
716 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 730 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
717 unsigned int level; 731 unsigned int level;
718 int lblock_ok; /* block passes checks */
719 732
720 /* magic number and level verification. 733 switch (block->bb_magic) {
734 case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
735 if (!xfs_sb_version_hascrc(&mp->m_sb))
736 return false;
737 if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
738 return false;
739 if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
740 return false;
741 /*
742 * XXX: need a better way of verifying the owner here. Right now
743 * just make sure there has been one set.
744 */
745 if (be64_to_cpu(block->bb_u.l.bb_owner) == 0)
746 return false;
747 /* fall through */
748 case cpu_to_be32(XFS_BMAP_MAGIC):
749 break;
750 default:
751 return false;
752 }
753
754 /*
755 * numrecs and level verification.
721 * 756 *
722 * We don't know waht fork we belong to, so just verify that the level 757 * We don't know what fork we belong to, so just verify that the level
723 * is less than the maximum of the two. Later checks will be more 758 * is less than the maximum of the two. Later checks will be more
724 * precise. 759 * precise.
725 */ 760 */
726 level = be16_to_cpu(block->bb_level); 761 level = be16_to_cpu(block->bb_level);
727 lblock_ok = block->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC) && 762 if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]))
728 level < max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]); 763 return false;
729 764 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0])
730 /* numrecs verification */ 765 return false;
731 lblock_ok = lblock_ok &&
732 be16_to_cpu(block->bb_numrecs) <= mp->m_bmap_dmxr[level != 0];
733 766
734 /* sibling pointer verification */ 767 /* sibling pointer verification */
735 lblock_ok = lblock_ok && 768 if (!block->bb_u.l.bb_leftsib ||
736 block->bb_u.l.bb_leftsib && 769 (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLDFSBNO) &&
737 (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) || 770 !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib))))
738 XFS_FSB_SANITY_CHECK(mp, 771 return false;
739 be64_to_cpu(block->bb_u.l.bb_leftsib))) && 772 if (!block->bb_u.l.bb_rightsib ||
740 block->bb_u.l.bb_rightsib && 773 (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLDFSBNO) &&
741 (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) || 774 !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib))))
742 XFS_FSB_SANITY_CHECK(mp, 775 return false;
743 be64_to_cpu(block->bb_u.l.bb_rightsib))); 776
744 777 return true;
745 if (!lblock_ok) { 778
746 trace_xfs_btree_corrupt(bp, _RET_IP_);
747 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
748 xfs_buf_ioerror(bp, EFSCORRUPTED);
749 }
750} 779}
751 780
752static void 781static void
753xfs_bmbt_read_verify( 782xfs_bmbt_read_verify(
754 struct xfs_buf *bp) 783 struct xfs_buf *bp)
755{ 784{
756 xfs_bmbt_verify(bp); 785 if (!(xfs_btree_lblock_verify_crc(bp) &&
786 xfs_bmbt_verify(bp))) {
787 trace_xfs_btree_corrupt(bp, _RET_IP_);
788 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
789 bp->b_target->bt_mount, bp->b_addr);
790 xfs_buf_ioerror(bp, EFSCORRUPTED);
791 }
792
757} 793}
758 794
759static void 795static void
760xfs_bmbt_write_verify( 796xfs_bmbt_write_verify(
761 struct xfs_buf *bp) 797 struct xfs_buf *bp)
762{ 798{
763 xfs_bmbt_verify(bp); 799 if (!xfs_bmbt_verify(bp)) {
800 xfs_warn(bp->b_target->bt_mount, "bmbt daddr 0x%llx failed", bp->b_bn);
801 trace_xfs_btree_corrupt(bp, _RET_IP_);
802 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
803 bp->b_target->bt_mount, bp->b_addr);
804 xfs_buf_ioerror(bp, EFSCORRUPTED);
805 return;
806 }
807 xfs_btree_lblock_calc_crc(bp);
764} 808}
765 809
766const struct xfs_buf_ops xfs_bmbt_buf_ops = { 810const struct xfs_buf_ops xfs_bmbt_buf_ops = {
@@ -838,6 +882,8 @@ xfs_bmbt_init_cursor(
838 882
839 cur->bc_ops = &xfs_bmbt_ops; 883 cur->bc_ops = &xfs_bmbt_ops;
840 cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; 884 cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;
885 if (xfs_sb_version_hascrc(&mp->m_sb))
886 cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
841 887
842 cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); 888 cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
843 cur->bc_private.b.ip = ip; 889 cur->bc_private.b.ip = ip;
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
index 88469ca08696..70c43d9f72c1 100644
--- a/fs/xfs/xfs_bmap_btree.h
+++ b/fs/xfs/xfs_bmap_btree.h
@@ -18,7 +18,8 @@
18#ifndef __XFS_BMAP_BTREE_H__ 18#ifndef __XFS_BMAP_BTREE_H__
19#define __XFS_BMAP_BTREE_H__ 19#define __XFS_BMAP_BTREE_H__
20 20
21#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ 21#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */
22#define XFS_BMAP_CRC_MAGIC 0x424d4133 /* 'BMA3' */
22 23
23struct xfs_btree_cur; 24struct xfs_btree_cur;
24struct xfs_btree_block; 25struct xfs_btree_block;
@@ -136,10 +137,10 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
136 137
137/* 138/*
138 * Btree block header size depends on a superblock flag. 139 * Btree block header size depends on a superblock flag.
139 *
140 * (not quite yet, but soon)
141 */ 140 */
142#define XFS_BMBT_BLOCK_LEN(mp) XFS_BTREE_LBLOCK_LEN 141#define XFS_BMBT_BLOCK_LEN(mp) \
142 (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
143 XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN)
143 144
144#define XFS_BMBT_REC_ADDR(mp, block, index) \ 145#define XFS_BMBT_REC_ADDR(mp, block, index) \
145 ((xfs_bmbt_rec_t *) \ 146 ((xfs_bmbt_rec_t *) \
@@ -186,12 +187,12 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
186#define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \ 187#define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \
187 XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0)) 188 XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0))
188 189
189#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \ 190#define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \
190 (int)(XFS_BTREE_LBLOCK_LEN + \ 191 (int)(XFS_BMBT_BLOCK_LEN(mp) + \
191 ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) 192 ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
192 193
193#define XFS_BMAP_BROOT_SPACE(bb) \ 194#define XFS_BMAP_BROOT_SPACE(mp, bb) \
194 (XFS_BMAP_BROOT_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs))) 195 (XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs)))
195#define XFS_BMDR_SPACE_CALC(nrecs) \ 196#define XFS_BMDR_SPACE_CALC(nrecs) \
196 (int)(sizeof(xfs_bmdr_block_t) + \ 197 (int)(sizeof(xfs_bmdr_block_t) + \
197 ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) 198 ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
@@ -204,7 +205,7 @@ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
204/* 205/*
205 * Prototypes for xfs_bmap.c to call. 206 * Prototypes for xfs_bmap.c to call.
206 */ 207 */
207extern void xfs_bmdr_to_bmbt(struct xfs_mount *, xfs_bmdr_block_t *, int, 208extern void xfs_bmdr_to_bmbt(struct xfs_inode *, xfs_bmdr_block_t *, int,
208 struct xfs_btree_block *, int); 209 struct xfs_btree_block *, int);
209extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); 210extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s);
210extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r); 211extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r);
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index db010408d701..ec77036f13b5 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -30,9 +30,11 @@
30#include "xfs_dinode.h" 30#include "xfs_dinode.h"
31#include "xfs_inode.h" 31#include "xfs_inode.h"
32#include "xfs_inode_item.h" 32#include "xfs_inode_item.h"
33#include "xfs_buf_item.h"
33#include "xfs_btree.h" 34#include "xfs_btree.h"
34#include "xfs_error.h" 35#include "xfs_error.h"
35#include "xfs_trace.h" 36#include "xfs_trace.h"
37#include "xfs_cksum.h"
36 38
37/* 39/*
38 * Cursor allocation zone. 40 * Cursor allocation zone.
@@ -42,9 +44,13 @@ kmem_zone_t *xfs_btree_cur_zone;
42/* 44/*
43 * Btree magic numbers. 45 * Btree magic numbers.
44 */ 46 */
45const __uint32_t xfs_magics[XFS_BTNUM_MAX] = { 47static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
46 XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC 48 { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC },
49 { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
50 XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC }
47}; 51};
52#define xfs_btree_magic(cur) \
53 xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
48 54
49 55
50STATIC int /* error (0 or EFSCORRUPTED) */ 56STATIC int /* error (0 or EFSCORRUPTED) */
@@ -54,30 +60,38 @@ xfs_btree_check_lblock(
54 int level, /* level of the btree block */ 60 int level, /* level of the btree block */
55 struct xfs_buf *bp) /* buffer for block, if any */ 61 struct xfs_buf *bp) /* buffer for block, if any */
56{ 62{
57 int lblock_ok; /* block passes checks */ 63 int lblock_ok = 1; /* block passes checks */
58 struct xfs_mount *mp; /* file system mount point */ 64 struct xfs_mount *mp; /* file system mount point */
59 65
60 mp = cur->bc_mp; 66 mp = cur->bc_mp;
61 lblock_ok = 67
62 be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] && 68 if (xfs_sb_version_hascrc(&mp->m_sb)) {
69 lblock_ok = lblock_ok &&
70 uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
71 block->bb_u.l.bb_blkno == cpu_to_be64(
72 bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
73 }
74
75 lblock_ok = lblock_ok &&
76 be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) &&
63 be16_to_cpu(block->bb_level) == level && 77 be16_to_cpu(block->bb_level) == level &&
64 be16_to_cpu(block->bb_numrecs) <= 78 be16_to_cpu(block->bb_numrecs) <=
65 cur->bc_ops->get_maxrecs(cur, level) && 79 cur->bc_ops->get_maxrecs(cur, level) &&
66 block->bb_u.l.bb_leftsib && 80 block->bb_u.l.bb_leftsib &&
67 (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) || 81 (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) ||
68 XFS_FSB_SANITY_CHECK(mp, 82 XFS_FSB_SANITY_CHECK(mp,
69 be64_to_cpu(block->bb_u.l.bb_leftsib))) && 83 be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
70 block->bb_u.l.bb_rightsib && 84 block->bb_u.l.bb_rightsib &&
71 (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) || 85 (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) ||
72 XFS_FSB_SANITY_CHECK(mp, 86 XFS_FSB_SANITY_CHECK(mp,
73 be64_to_cpu(block->bb_u.l.bb_rightsib))); 87 be64_to_cpu(block->bb_u.l.bb_rightsib)));
88
74 if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp, 89 if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp,
75 XFS_ERRTAG_BTREE_CHECK_LBLOCK, 90 XFS_ERRTAG_BTREE_CHECK_LBLOCK,
76 XFS_RANDOM_BTREE_CHECK_LBLOCK))) { 91 XFS_RANDOM_BTREE_CHECK_LBLOCK))) {
77 if (bp) 92 if (bp)
78 trace_xfs_btree_corrupt(bp, _RET_IP_); 93 trace_xfs_btree_corrupt(bp, _RET_IP_);
79 XFS_ERROR_REPORT("xfs_btree_check_lblock", XFS_ERRLEVEL_LOW, 94 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
80 mp);
81 return XFS_ERROR(EFSCORRUPTED); 95 return XFS_ERROR(EFSCORRUPTED);
82 } 96 }
83 return 0; 97 return 0;
@@ -90,16 +104,26 @@ xfs_btree_check_sblock(
90 int level, /* level of the btree block */ 104 int level, /* level of the btree block */
91 struct xfs_buf *bp) /* buffer containing block */ 105 struct xfs_buf *bp) /* buffer containing block */
92{ 106{
107 struct xfs_mount *mp; /* file system mount point */
93 struct xfs_buf *agbp; /* buffer for ag. freespace struct */ 108 struct xfs_buf *agbp; /* buffer for ag. freespace struct */
94 struct xfs_agf *agf; /* ag. freespace structure */ 109 struct xfs_agf *agf; /* ag. freespace structure */
95 xfs_agblock_t agflen; /* native ag. freespace length */ 110 xfs_agblock_t agflen; /* native ag. freespace length */
96 int sblock_ok; /* block passes checks */ 111 int sblock_ok = 1; /* block passes checks */
97 112
113 mp = cur->bc_mp;
98 agbp = cur->bc_private.a.agbp; 114 agbp = cur->bc_private.a.agbp;
99 agf = XFS_BUF_TO_AGF(agbp); 115 agf = XFS_BUF_TO_AGF(agbp);
100 agflen = be32_to_cpu(agf->agf_length); 116 agflen = be32_to_cpu(agf->agf_length);
101 sblock_ok = 117
102 be32_to_cpu(block->bb_magic) == xfs_magics[cur->bc_btnum] && 118 if (xfs_sb_version_hascrc(&mp->m_sb)) {
119 sblock_ok = sblock_ok &&
120 uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
121 block->bb_u.s.bb_blkno == cpu_to_be64(
122 bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
123 }
124
125 sblock_ok = sblock_ok &&
126 be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) &&
103 be16_to_cpu(block->bb_level) == level && 127 be16_to_cpu(block->bb_level) == level &&
104 be16_to_cpu(block->bb_numrecs) <= 128 be16_to_cpu(block->bb_numrecs) <=
105 cur->bc_ops->get_maxrecs(cur, level) && 129 cur->bc_ops->get_maxrecs(cur, level) &&
@@ -109,13 +133,13 @@ xfs_btree_check_sblock(
109 (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || 133 (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
110 be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) && 134 be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) &&
111 block->bb_u.s.bb_rightsib; 135 block->bb_u.s.bb_rightsib;
112 if (unlikely(XFS_TEST_ERROR(!sblock_ok, cur->bc_mp, 136
137 if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp,
113 XFS_ERRTAG_BTREE_CHECK_SBLOCK, 138 XFS_ERRTAG_BTREE_CHECK_SBLOCK,
114 XFS_RANDOM_BTREE_CHECK_SBLOCK))) { 139 XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
115 if (bp) 140 if (bp)
116 trace_xfs_btree_corrupt(bp, _RET_IP_); 141 trace_xfs_btree_corrupt(bp, _RET_IP_);
117 XFS_CORRUPTION_ERROR("xfs_btree_check_sblock", 142 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
118 XFS_ERRLEVEL_LOW, cur->bc_mp, block);
119 return XFS_ERROR(EFSCORRUPTED); 143 return XFS_ERROR(EFSCORRUPTED);
120 } 144 }
121 return 0; 145 return 0;
@@ -194,6 +218,72 @@ xfs_btree_check_ptr(
194#endif 218#endif
195 219
196/* 220/*
221 * Calculate CRC on the whole btree block and stuff it into the
222 * long-form btree header.
223 *
224 * Prior to calculting the CRC, pull the LSN out of the buffer log item and put
225 * it into the buffer so recovery knows what the last modifcation was that made
226 * it to disk.
227 */
228void
229xfs_btree_lblock_calc_crc(
230 struct xfs_buf *bp)
231{
232 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
233 struct xfs_buf_log_item *bip = bp->b_fspriv;
234
235 if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
236 return;
237 if (bip)
238 block->bb_u.l.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
239 xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
240 XFS_BTREE_LBLOCK_CRC_OFF);
241}
242
243bool
244xfs_btree_lblock_verify_crc(
245 struct xfs_buf *bp)
246{
247 if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
248 return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
249 XFS_BTREE_LBLOCK_CRC_OFF);
250 return true;
251}
252
253/*
254 * Calculate CRC on the whole btree block and stuff it into the
255 * short-form btree header.
256 *
257 * Prior to calculting the CRC, pull the LSN out of the buffer log item and put
258 * it into the buffer so recovery knows what the last modifcation was that made
259 * it to disk.
260 */
261void
262xfs_btree_sblock_calc_crc(
263 struct xfs_buf *bp)
264{
265 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
266 struct xfs_buf_log_item *bip = bp->b_fspriv;
267
268 if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
269 return;
270 if (bip)
271 block->bb_u.s.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
272 xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
273 XFS_BTREE_SBLOCK_CRC_OFF);
274}
275
276bool
277xfs_btree_sblock_verify_crc(
278 struct xfs_buf *bp)
279{
280 if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
281 return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
282 XFS_BTREE_SBLOCK_CRC_OFF);
283 return true;
284}
285
286/*
197 * Delete the btree cursor. 287 * Delete the btree cursor.
198 */ 288 */
199void 289void
@@ -277,10 +367,8 @@ xfs_btree_dup_cursor(
277 *ncur = NULL; 367 *ncur = NULL;
278 return error; 368 return error;
279 } 369 }
280 new->bc_bufs[i] = bp; 370 }
281 ASSERT(!xfs_buf_geterror(bp)); 371 new->bc_bufs[i] = bp;
282 } else
283 new->bc_bufs[i] = NULL;
284 } 372 }
285 *ncur = new; 373 *ncur = new;
286 return 0; 374 return 0;
@@ -321,9 +409,14 @@ xfs_btree_dup_cursor(
321 */ 409 */
322static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur) 410static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur)
323{ 411{
324 return (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? 412 if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
325 XFS_BTREE_LBLOCK_LEN : 413 if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS)
326 XFS_BTREE_SBLOCK_LEN; 414 return XFS_BTREE_LBLOCK_CRC_LEN;
415 return XFS_BTREE_LBLOCK_LEN;
416 }
417 if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS)
418 return XFS_BTREE_SBLOCK_CRC_LEN;
419 return XFS_BTREE_SBLOCK_LEN;
327} 420}
328 421
329/* 422/*
@@ -863,43 +956,85 @@ xfs_btree_set_sibling(
863} 956}
864 957
865void 958void
959xfs_btree_init_block_int(
960 struct xfs_mount *mp,
961 struct xfs_btree_block *buf,
962 xfs_daddr_t blkno,
963 __u32 magic,
964 __u16 level,
965 __u16 numrecs,
966 __u64 owner,
967 unsigned int flags)
968{
969 buf->bb_magic = cpu_to_be32(magic);
970 buf->bb_level = cpu_to_be16(level);
971 buf->bb_numrecs = cpu_to_be16(numrecs);
972
973 if (flags & XFS_BTREE_LONG_PTRS) {
974 buf->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
975 buf->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
976 if (flags & XFS_BTREE_CRC_BLOCKS) {
977 buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
978 buf->bb_u.l.bb_owner = cpu_to_be64(owner);
979 uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
980 buf->bb_u.l.bb_pad = 0;
981 }
982 } else {
983 /* owner is a 32 bit value on short blocks */
984 __u32 __owner = (__u32)owner;
985
986 buf->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
987 buf->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
988 if (flags & XFS_BTREE_CRC_BLOCKS) {
989 buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
990 buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
991 uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
992 }
993 }
994}
995
996void
866xfs_btree_init_block( 997xfs_btree_init_block(
867 struct xfs_mount *mp, 998 struct xfs_mount *mp,
868 struct xfs_buf *bp, 999 struct xfs_buf *bp,
869 __u32 magic, 1000 __u32 magic,
870 __u16 level, 1001 __u16 level,
871 __u16 numrecs, 1002 __u16 numrecs,
1003 __u64 owner,
872 unsigned int flags) 1004 unsigned int flags)
873{ 1005{
874 struct xfs_btree_block *new = XFS_BUF_TO_BLOCK(bp); 1006 xfs_btree_init_block_int(mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
875 1007 magic, level, numrecs, owner, flags);
876 new->bb_magic = cpu_to_be32(magic);
877 new->bb_level = cpu_to_be16(level);
878 new->bb_numrecs = cpu_to_be16(numrecs);
879
880 if (flags & XFS_BTREE_LONG_PTRS) {
881 new->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
882 new->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
883 } else {
884 new->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
885 new->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
886 }
887} 1008}
888 1009
889STATIC void 1010STATIC void
890xfs_btree_init_block_cur( 1011xfs_btree_init_block_cur(
891 struct xfs_btree_cur *cur, 1012 struct xfs_btree_cur *cur,
1013 struct xfs_buf *bp,
892 int level, 1014 int level,
893 int numrecs, 1015 int numrecs)
894 struct xfs_buf *bp)
895{ 1016{
896 xfs_btree_init_block(cur->bc_mp, bp, xfs_magics[cur->bc_btnum], 1017 __u64 owner;
897 level, numrecs, cur->bc_flags); 1018
1019 /*
1020 * we can pull the owner from the cursor right now as the different
1021 * owners align directly with the pointer size of the btree. This may
1022 * change in future, but is safe for current users of the generic btree
1023 * code.
1024 */
1025 if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
1026 owner = cur->bc_private.b.ip->i_ino;
1027 else
1028 owner = cur->bc_private.a.agno;
1029
1030 xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
1031 xfs_btree_magic(cur), level, numrecs,
1032 owner, cur->bc_flags);
898} 1033}
899 1034
900/* 1035/*
901 * Return true if ptr is the last record in the btree and 1036 * Return true if ptr is the last record in the btree and
902 * we need to track updateѕ to this record. The decision 1037 * we need to track updates to this record. The decision
903 * will be further refined in the update_lastrec method. 1038 * will be further refined in the update_lastrec method.
904 */ 1039 */
905STATIC int 1040STATIC int
@@ -1147,6 +1282,7 @@ xfs_btree_log_keys(
1147 XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); 1282 XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
1148 1283
1149 if (bp) { 1284 if (bp) {
1285 xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
1150 xfs_trans_log_buf(cur->bc_tp, bp, 1286 xfs_trans_log_buf(cur->bc_tp, bp,
1151 xfs_btree_key_offset(cur, first), 1287 xfs_btree_key_offset(cur, first),
1152 xfs_btree_key_offset(cur, last + 1) - 1); 1288 xfs_btree_key_offset(cur, last + 1) - 1);
@@ -1171,6 +1307,7 @@ xfs_btree_log_recs(
1171 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); 1307 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
1172 XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); 1308 XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
1173 1309
1310 xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
1174 xfs_trans_log_buf(cur->bc_tp, bp, 1311 xfs_trans_log_buf(cur->bc_tp, bp,
1175 xfs_btree_rec_offset(cur, first), 1312 xfs_btree_rec_offset(cur, first),
1176 xfs_btree_rec_offset(cur, last + 1) - 1); 1313 xfs_btree_rec_offset(cur, last + 1) - 1);
@@ -1195,6 +1332,7 @@ xfs_btree_log_ptrs(
1195 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 1332 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
1196 int level = xfs_btree_get_level(block); 1333 int level = xfs_btree_get_level(block);
1197 1334
1335 xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
1198 xfs_trans_log_buf(cur->bc_tp, bp, 1336 xfs_trans_log_buf(cur->bc_tp, bp,
1199 xfs_btree_ptr_offset(cur, first, level), 1337 xfs_btree_ptr_offset(cur, first, level),
1200 xfs_btree_ptr_offset(cur, last + 1, level) - 1); 1338 xfs_btree_ptr_offset(cur, last + 1, level) - 1);
@@ -1223,7 +1361,12 @@ xfs_btree_log_block(
1223 offsetof(struct xfs_btree_block, bb_numrecs), 1361 offsetof(struct xfs_btree_block, bb_numrecs),
1224 offsetof(struct xfs_btree_block, bb_u.s.bb_leftsib), 1362 offsetof(struct xfs_btree_block, bb_u.s.bb_leftsib),
1225 offsetof(struct xfs_btree_block, bb_u.s.bb_rightsib), 1363 offsetof(struct xfs_btree_block, bb_u.s.bb_rightsib),
1226 XFS_BTREE_SBLOCK_LEN 1364 offsetof(struct xfs_btree_block, bb_u.s.bb_blkno),
1365 offsetof(struct xfs_btree_block, bb_u.s.bb_lsn),
1366 offsetof(struct xfs_btree_block, bb_u.s.bb_uuid),
1367 offsetof(struct xfs_btree_block, bb_u.s.bb_owner),
1368 offsetof(struct xfs_btree_block, bb_u.s.bb_crc),
1369 XFS_BTREE_SBLOCK_CRC_LEN
1227 }; 1370 };
1228 static const short loffsets[] = { /* table of offsets (long) */ 1371 static const short loffsets[] = { /* table of offsets (long) */
1229 offsetof(struct xfs_btree_block, bb_magic), 1372 offsetof(struct xfs_btree_block, bb_magic),
@@ -1231,17 +1374,40 @@ xfs_btree_log_block(
1231 offsetof(struct xfs_btree_block, bb_numrecs), 1374 offsetof(struct xfs_btree_block, bb_numrecs),
1232 offsetof(struct xfs_btree_block, bb_u.l.bb_leftsib), 1375 offsetof(struct xfs_btree_block, bb_u.l.bb_leftsib),
1233 offsetof(struct xfs_btree_block, bb_u.l.bb_rightsib), 1376 offsetof(struct xfs_btree_block, bb_u.l.bb_rightsib),
1234 XFS_BTREE_LBLOCK_LEN 1377 offsetof(struct xfs_btree_block, bb_u.l.bb_blkno),
1378 offsetof(struct xfs_btree_block, bb_u.l.bb_lsn),
1379 offsetof(struct xfs_btree_block, bb_u.l.bb_uuid),
1380 offsetof(struct xfs_btree_block, bb_u.l.bb_owner),
1381 offsetof(struct xfs_btree_block, bb_u.l.bb_crc),
1382 offsetof(struct xfs_btree_block, bb_u.l.bb_pad),
1383 XFS_BTREE_LBLOCK_CRC_LEN
1235 }; 1384 };
1236 1385
1237 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); 1386 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
1238 XFS_BTREE_TRACE_ARGBI(cur, bp, fields); 1387 XFS_BTREE_TRACE_ARGBI(cur, bp, fields);
1239 1388
1240 if (bp) { 1389 if (bp) {
1390 int nbits;
1391
1392 if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) {
1393 /*
1394 * We don't log the CRC when updating a btree
1395 * block but instead recreate it during log
1396 * recovery. As the log buffers have checksums
1397 * of their own this is safe and avoids logging a crc
1398 * update in a lot of places.
1399 */
1400 if (fields == XFS_BB_ALL_BITS)
1401 fields = XFS_BB_ALL_BITS_CRC;
1402 nbits = XFS_BB_NUM_BITS_CRC;
1403 } else {
1404 nbits = XFS_BB_NUM_BITS;
1405 }
1241 xfs_btree_offsets(fields, 1406 xfs_btree_offsets(fields,
1242 (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? 1407 (cur->bc_flags & XFS_BTREE_LONG_PTRS) ?
1243 loffsets : soffsets, 1408 loffsets : soffsets,
1244 XFS_BB_NUM_BITS, &first, &last); 1409 nbits, &first, &last);
1410 xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
1245 xfs_trans_log_buf(cur->bc_tp, bp, first, last); 1411 xfs_trans_log_buf(cur->bc_tp, bp, first, last);
1246 } else { 1412 } else {
1247 xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, 1413 xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
@@ -2204,7 +2370,7 @@ xfs_btree_split(
2204 goto error0; 2370 goto error0;
2205 2371
2206 /* Fill in the btree header for the new right block. */ 2372 /* Fill in the btree header for the new right block. */
2207 xfs_btree_init_block_cur(cur, xfs_btree_get_level(left), 0, rbp); 2373 xfs_btree_init_block_cur(cur, rbp, xfs_btree_get_level(left), 0);
2208 2374
2209 /* 2375 /*
2210 * Split the entries between the old and the new block evenly. 2376 * Split the entries between the old and the new block evenly.
@@ -2513,7 +2679,7 @@ xfs_btree_new_root(
2513 nptr = 2; 2679 nptr = 2;
2514 } 2680 }
2515 /* Fill in the new block's btree header and log it. */ 2681 /* Fill in the new block's btree header and log it. */
2516 xfs_btree_init_block_cur(cur, cur->bc_nlevels, 2, nbp); 2682 xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2);
2517 xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS); 2683 xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS);
2518 ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) && 2684 ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) &&
2519 !xfs_btree_ptr_is_null(cur, &rptr)); 2685 !xfs_btree_ptr_is_null(cur, &rptr));
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h
index f932897194eb..6e6c915673fe 100644
--- a/fs/xfs/xfs_btree.h
+++ b/fs/xfs/xfs_btree.h
@@ -42,11 +42,15 @@ extern kmem_zone_t *xfs_btree_cur_zone;
42 * Generic btree header. 42 * Generic btree header.
43 * 43 *
44 * This is a combination of the actual format used on disk for short and long 44 * This is a combination of the actual format used on disk for short and long
45 * format btrees. The first three fields are shared by both format, but 45 * format btrees. The first three fields are shared by both format, but the
46 * the pointers are different and should be used with care. 46 * pointers are different and should be used with care.
47 * 47 *
48 * To get the size of the actual short or long form headers please use 48 * To get the size of the actual short or long form headers please use the size
49 * the size macros below. Never use sizeof(xfs_btree_block). 49 * macros below. Never use sizeof(xfs_btree_block).
50 *
51 * The blkno, crc, lsn, owner and uuid fields are only available in filesystems
52 * with the crc feature bit, and all accesses to them must be conditional on
53 * that flag.
50 */ 54 */
51struct xfs_btree_block { 55struct xfs_btree_block {
52 __be32 bb_magic; /* magic number for block type */ 56 __be32 bb_magic; /* magic number for block type */
@@ -56,10 +60,23 @@ struct xfs_btree_block {
56 struct { 60 struct {
57 __be32 bb_leftsib; 61 __be32 bb_leftsib;
58 __be32 bb_rightsib; 62 __be32 bb_rightsib;
63
64 __be64 bb_blkno;
65 __be64 bb_lsn;
66 uuid_t bb_uuid;
67 __be32 bb_owner;
68 __le32 bb_crc;
59 } s; /* short form pointers */ 69 } s; /* short form pointers */
60 struct { 70 struct {
61 __be64 bb_leftsib; 71 __be64 bb_leftsib;
62 __be64 bb_rightsib; 72 __be64 bb_rightsib;
73
74 __be64 bb_blkno;
75 __be64 bb_lsn;
76 uuid_t bb_uuid;
77 __be64 bb_owner;
78 __le32 bb_crc;
79 __be32 bb_pad; /* padding for alignment */
63 } l; /* long form pointers */ 80 } l; /* long form pointers */
64 } bb_u; /* rest */ 81 } bb_u; /* rest */
65}; 82};
@@ -67,6 +84,16 @@ struct xfs_btree_block {
67#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */ 84#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
68#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */ 85#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
69 86
87/* sizes of CRC enabled btree blocks */
88#define XFS_BTREE_SBLOCK_CRC_LEN (XFS_BTREE_SBLOCK_LEN + 40)
89#define XFS_BTREE_LBLOCK_CRC_LEN (XFS_BTREE_LBLOCK_LEN + 48)
90
91
92#define XFS_BTREE_SBLOCK_CRC_OFF \
93 offsetof(struct xfs_btree_block, bb_u.s.bb_crc)
94#define XFS_BTREE_LBLOCK_CRC_OFF \
95 offsetof(struct xfs_btree_block, bb_u.l.bb_crc)
96
70 97
71/* 98/*
72 * Generic key, ptr and record wrapper structures. 99 * Generic key, ptr and record wrapper structures.
@@ -101,13 +128,11 @@ union xfs_btree_rec {
101#define XFS_BB_NUMRECS 0x04 128#define XFS_BB_NUMRECS 0x04
102#define XFS_BB_LEFTSIB 0x08 129#define XFS_BB_LEFTSIB 0x08
103#define XFS_BB_RIGHTSIB 0x10 130#define XFS_BB_RIGHTSIB 0x10
131#define XFS_BB_BLKNO 0x20
104#define XFS_BB_NUM_BITS 5 132#define XFS_BB_NUM_BITS 5
105#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) 133#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1)
106 134#define XFS_BB_NUM_BITS_CRC 8
107/* 135#define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1)
108 * Magic numbers for btree blocks.
109 */
110extern const __uint32_t xfs_magics[];
111 136
112/* 137/*
113 * Generic stats interface 138 * Generic stats interface
@@ -256,6 +281,7 @@ typedef struct xfs_btree_cur
256#define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ 281#define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */
257#define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ 282#define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */
258#define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ 283#define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */
284#define XFS_BTREE_CRC_BLOCKS (1<<3) /* uses extended btree blocks */
259 285
260 286
261#define XFS_BTREE_NOERROR 0 287#define XFS_BTREE_NOERROR 0
@@ -393,8 +419,20 @@ xfs_btree_init_block(
393 __u32 magic, 419 __u32 magic,
394 __u16 level, 420 __u16 level,
395 __u16 numrecs, 421 __u16 numrecs,
422 __u64 owner,
396 unsigned int flags); 423 unsigned int flags);
397 424
425void
426xfs_btree_init_block_int(
427 struct xfs_mount *mp,
428 struct xfs_btree_block *buf,
429 xfs_daddr_t blkno,
430 __u32 magic,
431 __u16 level,
432 __u16 numrecs,
433 __u64 owner,
434 unsigned int flags);
435
398/* 436/*
399 * Common btree core entry points. 437 * Common btree core entry points.
400 */ 438 */
@@ -408,6 +446,14 @@ int xfs_btree_delete(struct xfs_btree_cur *, int *);
408int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); 446int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *);
409 447
410/* 448/*
449 * btree block CRC helpers
450 */
451void xfs_btree_lblock_calc_crc(struct xfs_buf *);
452bool xfs_btree_lblock_verify_crc(struct xfs_buf *);
453void xfs_btree_sblock_calc_crc(struct xfs_buf *);
454bool xfs_btree_sblock_verify_crc(struct xfs_buf *);
455
456/*
411 * Internal btree helpers also used by xfs_bmap.c. 457 * Internal btree helpers also used by xfs_bmap.c.
412 */ 458 */
413void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); 459void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int);
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index ee36c88ecfde..101ef8377f1b 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -24,19 +24,33 @@ extern kmem_zone_t *xfs_buf_item_zone;
24 * This flag indicates that the buffer contains on disk inodes 24 * This flag indicates that the buffer contains on disk inodes
25 * and requires special recovery handling. 25 * and requires special recovery handling.
26 */ 26 */
27#define XFS_BLF_INODE_BUF 0x1 27#define XFS_BLF_INODE_BUF (1<<0)
28/* 28/*
29 * This flag indicates that the buffer should not be replayed 29 * This flag indicates that the buffer should not be replayed
30 * during recovery because its blocks are being freed. 30 * during recovery because its blocks are being freed.
31 */ 31 */
32#define XFS_BLF_CANCEL 0x2 32#define XFS_BLF_CANCEL (1<<1)
33
33/* 34/*
34 * This flag indicates that the buffer contains on disk 35 * This flag indicates that the buffer contains on disk
35 * user or group dquots and may require special recovery handling. 36 * user or group dquots and may require special recovery handling.
36 */ 37 */
37#define XFS_BLF_UDQUOT_BUF 0x4 38#define XFS_BLF_UDQUOT_BUF (1<<2)
38#define XFS_BLF_PDQUOT_BUF 0x8 39#define XFS_BLF_PDQUOT_BUF (1<<3)
39#define XFS_BLF_GDQUOT_BUF 0x10 40#define XFS_BLF_GDQUOT_BUF (1<<4)
41
42/*
43 * all buffers now need flags to tell recovery where the magic number
44 * is so that it can verify and calculate the CRCs on the buffer correctly
45 * once the changes have been replayed into the buffer.
46 */
47#define XFS_BLF_BTREE_BUF (1<<5)
48
49#define XFS_BLF_TYPE_MASK \
50 (XFS_BLF_UDQUOT_BUF | \
51 XFS_BLF_PDQUOT_BUF | \
52 XFS_BLF_GDQUOT_BUF | \
53 XFS_BLF_BTREE_BUF)
40 54
41#define XFS_BLF_CHUNK 128 55#define XFS_BLF_CHUNK 128
42#define XFS_BLF_SHIFT 7 56#define XFS_BLF_SHIFT 7
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h
index 88a3368ef124..6b5bd1745dbe 100644
--- a/fs/xfs/xfs_dinode.h
+++ b/fs/xfs/xfs_dinode.h
@@ -107,8 +107,8 @@ typedef enum xfs_dinode_fmt {
107#define XFS_LITINO(mp, version) \ 107#define XFS_LITINO(mp, version) \
108 ((int)(((mp)->m_sb.sb_inodesize) - sizeof(struct xfs_dinode))) 108 ((int)(((mp)->m_sb.sb_inodesize) - sizeof(struct xfs_dinode)))
109 109
110#define XFS_BROOT_SIZE_ADJ \ 110#define XFS_BROOT_SIZE_ADJ(ip) \
111 (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t)) 111 (XFS_BMBT_BLOCK_LEN((ip)->i_mount) - sizeof(xfs_bmdr_block_t))
112 112
113/* 113/*
114 * Inode data & attribute fork sizes, per inode. 114 * Inode data & attribute fork sizes, per inode.
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 2866b8c78b7a..6fe286a8e29b 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -316,7 +316,13 @@ xfs_growfs_data_private(
316 goto error0; 316 goto error0;
317 } 317 }
318 318
319 xfs_btree_init_block(mp, bp, XFS_ABTB_MAGIC, 0, 1, 0); 319 if (xfs_sb_version_hascrc(&mp->m_sb))
320 xfs_btree_init_block(mp, bp, XFS_ABTB_CRC_MAGIC, 0, 1,
321 agno, XFS_BTREE_CRC_BLOCKS);
322 else
323 xfs_btree_init_block(mp, bp, XFS_ABTB_MAGIC, 0, 1,
324 agno, 0);
325
320 arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); 326 arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
321 arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp)); 327 arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
322 arec->ar_blockcount = cpu_to_be32( 328 arec->ar_blockcount = cpu_to_be32(
@@ -339,7 +345,13 @@ xfs_growfs_data_private(
339 goto error0; 345 goto error0;
340 } 346 }
341 347
342 xfs_btree_init_block(mp, bp, XFS_ABTC_MAGIC, 0, 1, 0); 348 if (xfs_sb_version_hascrc(&mp->m_sb))
349 xfs_btree_init_block(mp, bp, XFS_ABTC_CRC_MAGIC, 0, 1,
350 agno, XFS_BTREE_CRC_BLOCKS);
351 else
352 xfs_btree_init_block(mp, bp, XFS_ABTC_MAGIC, 0, 1,
353 agno, 0);
354
343 arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); 355 arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
344 arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp)); 356 arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
345 arec->ar_blockcount = cpu_to_be32( 357 arec->ar_blockcount = cpu_to_be32(
@@ -363,7 +375,12 @@ xfs_growfs_data_private(
363 goto error0; 375 goto error0;
364 } 376 }
365 377
366 xfs_btree_init_block(mp, bp, XFS_IBT_MAGIC, 0, 0, 0); 378 if (xfs_sb_version_hascrc(&mp->m_sb))
379 xfs_btree_init_block(mp, bp, XFS_IBT_CRC_MAGIC, 0, 0,
380 agno, XFS_BTREE_CRC_BLOCKS);
381 else
382 xfs_btree_init_block(mp, bp, XFS_IBT_MAGIC, 0, 0,
383 agno, 0);
367 384
368 error = xfs_bwrite(bp); 385 error = xfs_bwrite(bp);
369 xfs_buf_relse(bp); 386 xfs_buf_relse(bp);
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
index bec344b36507..c82ac8867421 100644
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -34,6 +34,7 @@
34#include "xfs_alloc.h" 34#include "xfs_alloc.h"
35#include "xfs_error.h" 35#include "xfs_error.h"
36#include "xfs_trace.h" 36#include "xfs_trace.h"
37#include "xfs_cksum.h"
37 38
38 39
39STATIC int 40STATIC int
@@ -182,52 +183,88 @@ xfs_inobt_key_diff(
182 cur->bc_rec.i.ir_startino; 183 cur->bc_rec.i.ir_startino;
183} 184}
184 185
185void 186static int
186xfs_inobt_verify( 187xfs_inobt_verify(
187 struct xfs_buf *bp) 188 struct xfs_buf *bp)
188{ 189{
189 struct xfs_mount *mp = bp->b_target->bt_mount; 190 struct xfs_mount *mp = bp->b_target->bt_mount;
190 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 191 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
192 struct xfs_perag *pag = bp->b_pag;
191 unsigned int level; 193 unsigned int level;
192 int sblock_ok; /* block passes checks */
193 194
194 /* magic number and level verification */ 195 /*
195 level = be16_to_cpu(block->bb_level); 196 * During growfs operations, we can't verify the exact owner as the
196 sblock_ok = block->bb_magic == cpu_to_be32(XFS_IBT_MAGIC) && 197 * perag is not fully initialised and hence not attached to the buffer.
197 level < mp->m_in_maxlevels; 198 *
199 * Similarly, during log recovery we will have a perag structure
200 * attached, but the agi information will not yet have been initialised
201 * from the on disk AGI. We don't currently use any of this information,
202 * but beware of the landmine (i.e. need to check pag->pagi_init) if we
203 * ever do.
204 */
205 switch (block->bb_magic) {
206 case cpu_to_be32(XFS_IBT_CRC_MAGIC):
207 if (!xfs_sb_version_hascrc(&mp->m_sb))
208 return false;
209 if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
210 return false;
211 if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
212 return false;
213 if (pag &&
214 be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
215 return false;
216 /* fall through */
217 case cpu_to_be32(XFS_IBT_MAGIC):
218 break;
219 default:
220 return 0;
221 }
198 222
199 /* numrecs verification */ 223 /* numrecs and level verification */
200 sblock_ok = sblock_ok && 224 level = be16_to_cpu(block->bb_level);
201 be16_to_cpu(block->bb_numrecs) <= mp->m_inobt_mxr[level != 0]; 225 if (level >= mp->m_in_maxlevels)
226 return false;
227 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[level != 0])
228 return false;
202 229
203 /* sibling pointer verification */ 230 /* sibling pointer verification */
204 sblock_ok = sblock_ok && 231 if (!block->bb_u.s.bb_leftsib ||
205 (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || 232 (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
206 be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) && 233 block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
207 block->bb_u.s.bb_leftsib && 234 return false;
208 (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || 235 if (!block->bb_u.s.bb_rightsib ||
209 be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) && 236 (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
210 block->bb_u.s.bb_rightsib; 237 block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
211 238 return false;
212 if (!sblock_ok) { 239
213 trace_xfs_btree_corrupt(bp, _RET_IP_); 240 return true;
214 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
215 xfs_buf_ioerror(bp, EFSCORRUPTED);
216 }
217} 241}
218 242
219static void 243static void
220xfs_inobt_read_verify( 244xfs_inobt_read_verify(
221 struct xfs_buf *bp) 245 struct xfs_buf *bp)
222{ 246{
223 xfs_inobt_verify(bp); 247 if (!(xfs_btree_sblock_verify_crc(bp) &&
248 xfs_inobt_verify(bp))) {
249 trace_xfs_btree_corrupt(bp, _RET_IP_);
250 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
251 bp->b_target->bt_mount, bp->b_addr);
252 xfs_buf_ioerror(bp, EFSCORRUPTED);
253 }
224} 254}
225 255
226static void 256static void
227xfs_inobt_write_verify( 257xfs_inobt_write_verify(
228 struct xfs_buf *bp) 258 struct xfs_buf *bp)
229{ 259{
230 xfs_inobt_verify(bp); 260 if (!xfs_inobt_verify(bp)) {
261 trace_xfs_btree_corrupt(bp, _RET_IP_);
262 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
263 bp->b_target->bt_mount, bp->b_addr);
264 xfs_buf_ioerror(bp, EFSCORRUPTED);
265 }
266 xfs_btree_sblock_calc_crc(bp);
267
231} 268}
232 269
233const struct xfs_buf_ops xfs_inobt_buf_ops = { 270const struct xfs_buf_ops xfs_inobt_buf_ops = {
@@ -301,6 +338,8 @@ xfs_inobt_init_cursor(
301 cur->bc_blocklog = mp->m_sb.sb_blocklog; 338 cur->bc_blocklog = mp->m_sb.sb_blocklog;
302 339
303 cur->bc_ops = &xfs_inobt_ops; 340 cur->bc_ops = &xfs_inobt_ops;
341 if (xfs_sb_version_hascrc(&mp->m_sb))
342 cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
304 343
305 cur->bc_private.a.agbp = agbp; 344 cur->bc_private.a.agbp = agbp;
306 cur->bc_private.a.agno = agno; 345 cur->bc_private.a.agno = agno;
diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h
index 25c0239a8eab..3ac36b7642e9 100644
--- a/fs/xfs/xfs_ialloc_btree.h
+++ b/fs/xfs/xfs_ialloc_btree.h
@@ -29,7 +29,8 @@ struct xfs_mount;
29/* 29/*
30 * There is a btree for the inode map per allocation group. 30 * There is a btree for the inode map per allocation group.
31 */ 31 */
32#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ 32#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */
33#define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */
33 34
34typedef __uint64_t xfs_inofree_t; 35typedef __uint64_t xfs_inofree_t;
35#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) 36#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t))
@@ -76,10 +77,10 @@ typedef __be32 xfs_inobt_ptr_t;
76 77
77/* 78/*
78 * Btree block header size depends on a superblock flag. 79 * Btree block header size depends on a superblock flag.
79 *
80 * (not quite yet, but soon)
81 */ 80 */
82#define XFS_INOBT_BLOCK_LEN(mp) XFS_BTREE_SBLOCK_LEN 81#define XFS_INOBT_BLOCK_LEN(mp) \
82 (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
83 XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN)
83 84
84/* 85/*
85 * Record, key, and pointer address macros for btree blocks. 86 * Record, key, and pointer address macros for btree blocks.
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 4f201656d2d9..202ce37e66cb 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -786,6 +786,7 @@ xfs_iformat_btree(
786 xfs_dinode_t *dip, 786 xfs_dinode_t *dip,
787 int whichfork) 787 int whichfork)
788{ 788{
789 struct xfs_mount *mp = ip->i_mount;
789 xfs_bmdr_block_t *dfp; 790 xfs_bmdr_block_t *dfp;
790 xfs_ifork_t *ifp; 791 xfs_ifork_t *ifp;
791 /* REFERENCED */ 792 /* REFERENCED */
@@ -794,7 +795,7 @@ xfs_iformat_btree(
794 795
795 ifp = XFS_IFORK_PTR(ip, whichfork); 796 ifp = XFS_IFORK_PTR(ip, whichfork);
796 dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); 797 dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
797 size = XFS_BMAP_BROOT_SPACE(dfp); 798 size = XFS_BMAP_BROOT_SPACE(mp, dfp);
798 nrecs = be16_to_cpu(dfp->bb_numrecs); 799 nrecs = be16_to_cpu(dfp->bb_numrecs);
799 800
800 /* 801 /*
@@ -805,14 +806,14 @@ xfs_iformat_btree(
805 * blocks. 806 * blocks.
806 */ 807 */
807 if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= 808 if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
808 XFS_IFORK_MAXEXT(ip, whichfork) || 809 XFS_IFORK_MAXEXT(ip, whichfork) ||
809 XFS_BMDR_SPACE_CALC(nrecs) > 810 XFS_BMDR_SPACE_CALC(nrecs) >
810 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork) || 811 XFS_DFORK_SIZE(dip, mp, whichfork) ||
811 XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { 812 XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
812 xfs_warn(ip->i_mount, "corrupt inode %Lu (btree).", 813 xfs_warn(mp, "corrupt inode %Lu (btree).",
813 (unsigned long long) ip->i_ino); 814 (unsigned long long) ip->i_ino);
814 XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW, 815 XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
815 ip->i_mount, dip); 816 mp, dip);
816 return XFS_ERROR(EFSCORRUPTED); 817 return XFS_ERROR(EFSCORRUPTED);
817 } 818 }
818 819
@@ -823,8 +824,7 @@ xfs_iformat_btree(
823 * Copy and convert from the on-disk structure 824 * Copy and convert from the on-disk structure
824 * to the in-memory structure. 825 * to the in-memory structure.
825 */ 826 */
826 xfs_bmdr_to_bmbt(ip->i_mount, dfp, 827 xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
827 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
828 ifp->if_broot, size); 828 ifp->if_broot, size);
829 ifp->if_flags &= ~XFS_IFEXTENTS; 829 ifp->if_flags &= ~XFS_IFEXTENTS;
830 ifp->if_flags |= XFS_IFBROOT; 830 ifp->if_flags |= XFS_IFBROOT;
@@ -2037,7 +2037,7 @@ xfs_iroot_realloc(
2037 * allocate it now and get out. 2037 * allocate it now and get out.
2038 */ 2038 */
2039 if (ifp->if_broot_bytes == 0) { 2039 if (ifp->if_broot_bytes == 0) {
2040 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff); 2040 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
2041 ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); 2041 ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
2042 ifp->if_broot_bytes = (int)new_size; 2042 ifp->if_broot_bytes = (int)new_size;
2043 return; 2043 return;
@@ -2051,9 +2051,9 @@ xfs_iroot_realloc(
2051 */ 2051 */
2052 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); 2052 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
2053 new_max = cur_max + rec_diff; 2053 new_max = cur_max + rec_diff;
2054 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); 2054 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
2055 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, 2055 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
2056 (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */ 2056 XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max),
2057 KM_SLEEP | KM_NOFS); 2057 KM_SLEEP | KM_NOFS);
2058 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, 2058 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2059 ifp->if_broot_bytes); 2059 ifp->if_broot_bytes);
@@ -2061,7 +2061,7 @@ xfs_iroot_realloc(
2061 (int)new_size); 2061 (int)new_size);
2062 ifp->if_broot_bytes = (int)new_size; 2062 ifp->if_broot_bytes = (int)new_size;
2063 ASSERT(ifp->if_broot_bytes <= 2063 ASSERT(ifp->if_broot_bytes <=
2064 XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); 2064 XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip));
2065 memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t)); 2065 memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
2066 return; 2066 return;
2067 } 2067 }
@@ -2076,7 +2076,7 @@ xfs_iroot_realloc(
2076 new_max = cur_max + rec_diff; 2076 new_max = cur_max + rec_diff;
2077 ASSERT(new_max >= 0); 2077 ASSERT(new_max >= 0);
2078 if (new_max > 0) 2078 if (new_max > 0)
2079 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); 2079 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
2080 else 2080 else
2081 new_size = 0; 2081 new_size = 0;
2082 if (new_size > 0) { 2082 if (new_size > 0) {
@@ -2084,7 +2084,8 @@ xfs_iroot_realloc(
2084 /* 2084 /*
2085 * First copy over the btree block header. 2085 * First copy over the btree block header.
2086 */ 2086 */
2087 memcpy(new_broot, ifp->if_broot, XFS_BTREE_LBLOCK_LEN); 2087 memcpy(new_broot, ifp->if_broot,
2088 XFS_BMBT_BLOCK_LEN(ip->i_mount));
2088 } else { 2089 } else {
2089 new_broot = NULL; 2090 new_broot = NULL;
2090 ifp->if_flags &= ~XFS_IFBROOT; 2091 ifp->if_flags &= ~XFS_IFBROOT;
@@ -2114,7 +2115,7 @@ xfs_iroot_realloc(
2114 ifp->if_broot = new_broot; 2115 ifp->if_broot = new_broot;
2115 ifp->if_broot_bytes = (int)new_size; 2116 ifp->if_broot_bytes = (int)new_size;
2116 ASSERT(ifp->if_broot_bytes <= 2117 ASSERT(ifp->if_broot_bytes <=
2117 XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); 2118 XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip));
2118 return; 2119 return;
2119} 2120}
2120 2121
@@ -2427,7 +2428,7 @@ xfs_iflush_fork(
2427 ASSERT(ifp->if_broot != NULL); 2428 ASSERT(ifp->if_broot != NULL);
2428 ASSERT(ifp->if_broot_bytes <= 2429 ASSERT(ifp->if_broot_bytes <=
2429 (XFS_IFORK_SIZE(ip, whichfork) + 2430 (XFS_IFORK_SIZE(ip, whichfork) +
2430 XFS_BROOT_SIZE_ADJ)); 2431 XFS_BROOT_SIZE_ADJ(ip)));
2431 xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes, 2432 xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
2432 (xfs_bmdr_block_t *)cp, 2433 (xfs_bmdr_block_t *)cp,
2433 XFS_DFORK_SIZE(dip, mp, whichfork)); 2434 XFS_DFORK_SIZE(dip, mp, whichfork));
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 3ca3380c3afe..3762ce2e99fc 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -29,6 +29,7 @@
29#include "xfs_bmap_btree.h" 29#include "xfs_bmap_btree.h"
30#include "xfs_alloc_btree.h" 30#include "xfs_alloc_btree.h"
31#include "xfs_ialloc_btree.h" 31#include "xfs_ialloc_btree.h"
32#include "xfs_btree.h"
32#include "xfs_dinode.h" 33#include "xfs_dinode.h"
33#include "xfs_inode.h" 34#include "xfs_inode.h"
34#include "xfs_inode_item.h" 35#include "xfs_inode_item.h"
@@ -1928,6 +1929,33 @@ xlog_recover_do_reg_buffer(
1928 1929
1929 /* Shouldn't be any more regions */ 1930 /* Shouldn't be any more regions */
1930 ASSERT(i == item->ri_total); 1931 ASSERT(i == item->ri_total);
1932
1933 switch (buf_f->blf_flags & XFS_BLF_TYPE_MASK) {
1934 case XFS_BLF_BTREE_BUF:
1935 switch (be32_to_cpu(*(__be32 *)bp->b_addr)) {
1936 case XFS_ABTB_CRC_MAGIC:
1937 case XFS_ABTC_CRC_MAGIC:
1938 case XFS_ABTB_MAGIC:
1939 case XFS_ABTC_MAGIC:
1940 bp->b_ops = &xfs_allocbt_buf_ops;
1941 break;
1942 case XFS_IBT_CRC_MAGIC:
1943 case XFS_IBT_MAGIC:
1944 bp->b_ops = &xfs_inobt_buf_ops;
1945 break;
1946 case XFS_BMAP_CRC_MAGIC:
1947 case XFS_BMAP_MAGIC:
1948 bp->b_ops = &xfs_bmbt_buf_ops;
1949 break;
1950 default:
1951 xfs_warn(mp, "Bad btree block magic!");
1952 ASSERT(0);
1953 break;
1954 }
1955 break;
1956 default:
1957 break;
1958 }
1931} 1959}
1932 1960
1933/* 1961/*
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index cd29f6171021..1b04fe59c603 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -505,6 +505,8 @@ void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
505void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); 505void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
506void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); 506void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
507void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); 507void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
508void xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *,
509 uint);
508void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); 510void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
509void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); 511void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
510void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); 512void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 3edf5dbee001..f950edd0d537 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -659,6 +659,7 @@ xfs_trans_binval(
659 ASSERT(XFS_BUF_ISSTALE(bp)); 659 ASSERT(XFS_BUF_ISSTALE(bp));
660 ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY))); 660 ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
661 ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_INODE_BUF)); 661 ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_INODE_BUF));
662 ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_TYPE_MASK));
662 ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); 663 ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
663 ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY); 664 ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY);
664 ASSERT(tp->t_flags & XFS_TRANS_DIRTY); 665 ASSERT(tp->t_flags & XFS_TRANS_DIRTY);
@@ -671,6 +672,7 @@ xfs_trans_binval(
671 bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY); 672 bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY);
672 bip->__bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; 673 bip->__bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
673 bip->__bli_format.blf_flags |= XFS_BLF_CANCEL; 674 bip->__bli_format.blf_flags |= XFS_BLF_CANCEL;
675 bip->__bli_format.blf_flags &= ~XFS_BLF_TYPE_MASK;
674 for (i = 0; i < bip->bli_format_count; i++) { 676 for (i = 0; i < bip->bli_format_count; i++) {
675 memset(bip->bli_formats[i].blf_data_map, 0, 677 memset(bip->bli_formats[i].blf_data_map, 0,
676 (bip->bli_formats[i].blf_map_size * sizeof(uint))); 678 (bip->bli_formats[i].blf_map_size * sizeof(uint)));
@@ -751,6 +753,26 @@ xfs_trans_inode_alloc_buf(
751 bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; 753 bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF;
752} 754}
753 755
756/*
757 * Set the type of the buffer for log recovery so that it can correctly identify
758 * and hence attach the correct buffer ops to the buffer after replay.
759 */
760void
761xfs_trans_buf_set_type(
762 struct xfs_trans *tp,
763 struct xfs_buf *bp,
764 uint type)
765{
766 struct xfs_buf_log_item *bip = bp->b_fspriv;
767
768 ASSERT(bp->b_transp == tp);
769 ASSERT(bip != NULL);
770 ASSERT(atomic_read(&bip->bli_refcount) > 0);
771 ASSERT((type & XFS_BLF_TYPE_MASK) != 0);
772
773 bip->__bli_format.blf_flags &= ~XFS_BLF_TYPE_MASK;
774 bip->__bli_format.blf_flags |= type;
775}
754 776
755/* 777/*
756 * Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of 778 * Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of
@@ -769,14 +791,9 @@ xfs_trans_dquot_buf(
769 xfs_buf_t *bp, 791 xfs_buf_t *bp,
770 uint type) 792 uint type)
771{ 793{
772 xfs_buf_log_item_t *bip = bp->b_fspriv;
773
774 ASSERT(bp->b_transp == tp);
775 ASSERT(bip != NULL);
776 ASSERT(type == XFS_BLF_UDQUOT_BUF || 794 ASSERT(type == XFS_BLF_UDQUOT_BUF ||
777 type == XFS_BLF_PDQUOT_BUF || 795 type == XFS_BLF_PDQUOT_BUF ||
778 type == XFS_BLF_GDQUOT_BUF); 796 type == XFS_BLF_GDQUOT_BUF);
779 ASSERT(atomic_read(&bip->bli_refcount) > 0);
780 797
781 bip->__bli_format.blf_flags |= type; 798 xfs_trans_buf_set_type(tp, bp, type);
782} 799}