diff options
-rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 105 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc_btree.h | 12 | ||||
-rw-r--r-- | fs/xfs/xfs_attr_leaf.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap.c | 47 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 110 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.h | 19 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.c | 256 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.h | 64 | ||||
-rw-r--r-- | fs/xfs/xfs_buf_item.h | 24 | ||||
-rw-r--r-- | fs/xfs/xfs_dinode.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_fsops.c | 23 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 87 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.h | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 33 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 28 | ||||
-rw-r--r-- | fs/xfs/xfs_trans.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_buf.c | 29 |
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 | ||
38 | STATIC struct xfs_btree_cur * | 39 | STATIC 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 | ||
275 | static void | 276 | static bool |
276 | xfs_allocbt_verify( | 277 | xfs_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 | ||
331 | static void | 356 | static void |
332 | xfs_allocbt_read_verify( | 357 | xfs_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 | ||
338 | static void | 369 | static void |
339 | xfs_allocbt_write_verify( | 370 | xfs_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 | ||
345 | const struct xfs_buf_ops xfs_allocbt_buf_ops = { | 383 | const 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 | */ |
1315 | STATIC void | 1328 | STATIC void |
1316 | xfs_bmap_local_to_extents_init_fn( | 1329 | xfs_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 | ||
1325 | STATIC void | 1340 | STATIC void |
1326 | xfs_symlink_local_to_remote( | 1341 | xfs_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 | */ |
1348 | STATIC int /* error */ | 1363 | STATIC int /* error */ |
1349 | xfs_bmap_add_attrfork_local( | 1364 | xfs_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 | */ |
60 | void | 61 | void |
61 | xfs_bmdr_to_bmbt( | 62 | xfs_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 | ||
711 | static void | 725 | static int |
712 | xfs_bmbt_verify( | 726 | xfs_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 | ||
752 | static void | 781 | static void |
753 | xfs_bmbt_read_verify( | 782 | xfs_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 | ||
759 | static void | 795 | static void |
760 | xfs_bmbt_write_verify( | 796 | xfs_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 | ||
766 | const struct xfs_buf_ops xfs_bmbt_buf_ops = { | 810 | const 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 | ||
23 | struct xfs_btree_cur; | 24 | struct xfs_btree_cur; |
24 | struct xfs_btree_block; | 25 | struct 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 | */ |
207 | extern void xfs_bmdr_to_bmbt(struct xfs_mount *, xfs_bmdr_block_t *, int, | 208 | extern 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); |
209 | extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); | 210 | extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); |
210 | extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r); | 211 | extern 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 | */ |
45 | const __uint32_t xfs_magics[XFS_BTNUM_MAX] = { | 47 | static 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 | ||
50 | STATIC int /* error (0 or EFSCORRUPTED) */ | 56 | STATIC 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 | */ | ||
228 | void | ||
229 | xfs_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 | |||
243 | bool | ||
244 | xfs_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 | */ | ||
261 | void | ||
262 | xfs_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 | |||
276 | bool | ||
277 | xfs_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 | */ |
199 | void | 289 | void |
@@ -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 | */ |
322 | static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur) | 410 | static 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 | ||
865 | void | 958 | void |
959 | xfs_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 | |||
996 | void | ||
866 | xfs_btree_init_block( | 997 | xfs_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 | ||
889 | STATIC void | 1010 | STATIC void |
890 | xfs_btree_init_block_cur( | 1011 | xfs_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 | */ |
905 | STATIC int | 1040 | STATIC 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 | */ |
51 | struct xfs_btree_block { | 55 | struct 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 | */ | ||
110 | extern 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 | ||
425 | void | ||
426 | xfs_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 *); | |||
408 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); | 446 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); |
409 | 447 | ||
410 | /* | 448 | /* |
449 | * btree block CRC helpers | ||
450 | */ | ||
451 | void xfs_btree_lblock_calc_crc(struct xfs_buf *); | ||
452 | bool xfs_btree_lblock_verify_crc(struct xfs_buf *); | ||
453 | void xfs_btree_sblock_calc_crc(struct xfs_buf *); | ||
454 | bool 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 | */ |
413 | void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); | 459 | void 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 | ||
39 | STATIC int | 40 | STATIC 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 | ||
185 | void | 186 | static int |
186 | xfs_inobt_verify( | 187 | xfs_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 | ||
219 | static void | 243 | static void |
220 | xfs_inobt_read_verify( | 244 | xfs_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 | ||
226 | static void | 256 | static void |
227 | xfs_inobt_write_verify( | 257 | xfs_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 | ||
233 | const struct xfs_buf_ops xfs_inobt_buf_ops = { | 270 | const 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 | ||
34 | typedef __uint64_t xfs_inofree_t; | 35 | typedef __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 *); | |||
505 | void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); | 505 | void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); |
506 | void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); | 506 | void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); |
507 | void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); | 507 | void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); |
508 | void xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *, | ||
509 | uint); | ||
508 | void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); | 510 | void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); |
509 | void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); | 511 | void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); |
510 | void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); | 512 | void 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 | */ | ||
760 | void | ||
761 | xfs_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 | } |