aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik2013-04-05 15:50:09 -0500
committerGreg Kroah-Hartman2013-04-25 14:51:24 -0500
commitc5627099f70b1187b84fa711f6b5daf32f16b10e (patch)
tree148052c282d39af398e09a2785f2e8772ff17041 /fs
parentfdb6d5c17e8fe339de73879c18d5084ca3264e86 (diff)
downloadkernel-omap-c5627099f70b1187b84fa711f6b5daf32f16b10e.tar.gz
kernel-omap-c5627099f70b1187b84fa711f6b5daf32f16b10e.tar.xz
kernel-omap-c5627099f70b1187b84fa711f6b5daf32f16b10e.zip
Btrfs: make sure nbytes are right after log replay
commit 4bc4bee4595662d8bff92180d5c32e3313a704b0 upstream. While trying to track down a tree log replay bug I noticed that fsck was always complaining about nbytes not being right for our fsynced file. That is because the new fsync stuff doesn't wait for ordered extents to complete, so the inodes nbytes are not necessarily updated properly when we log it. So to fix this we need to set nbytes to whatever it is on the inode that is on disk, so when we replay the extents we can just add the bytes that are being added as we replay the extent. This makes it work for the case that we have the wrong nbytes or the case that we logged everything and nbytes is actually correct. With this I'm no longer getting nbytes errors out of btrfsck. Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com> Signed-off-by: Lingzhu Xiang <lxiang@redhat.com> Reviewed-by: CAI Qian <caiqian@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/tree-log.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 744a69b2eb0f..8a00e2f00dc6 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -318,6 +318,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
318 unsigned long src_ptr; 318 unsigned long src_ptr;
319 unsigned long dst_ptr; 319 unsigned long dst_ptr;
320 int overwrite_root = 0; 320 int overwrite_root = 0;
321 bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
321 322
322 if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) 323 if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
323 overwrite_root = 1; 324 overwrite_root = 1;
@@ -327,6 +328,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
327 328
328 /* look for the key in the destination tree */ 329 /* look for the key in the destination tree */
329 ret = btrfs_search_slot(NULL, root, key, path, 0, 0); 330 ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
331 if (ret < 0)
332 return ret;
333
330 if (ret == 0) { 334 if (ret == 0) {
331 char *src_copy; 335 char *src_copy;
332 char *dst_copy; 336 char *dst_copy;
@@ -368,6 +372,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
368 return 0; 372 return 0;
369 } 373 }
370 374
375 /*
376 * We need to load the old nbytes into the inode so when we
377 * replay the extents we've logged we get the right nbytes.
378 */
379 if (inode_item) {
380 struct btrfs_inode_item *item;
381 u64 nbytes;
382
383 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
384 struct btrfs_inode_item);
385 nbytes = btrfs_inode_nbytes(path->nodes[0], item);
386 item = btrfs_item_ptr(eb, slot,
387 struct btrfs_inode_item);
388 btrfs_set_inode_nbytes(eb, item, nbytes);
389 }
390 } else if (inode_item) {
391 struct btrfs_inode_item *item;
392
393 /*
394 * New inode, set nbytes to 0 so that the nbytes comes out
395 * properly when we replay the extents.
396 */
397 item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item);
398 btrfs_set_inode_nbytes(eb, item, 0);
371 } 399 }
372insert: 400insert:
373 btrfs_release_path(path); 401 btrfs_release_path(path);
@@ -488,7 +516,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
488 u64 mask = root->sectorsize - 1; 516 u64 mask = root->sectorsize - 1;
489 u64 extent_end; 517 u64 extent_end;
490 u64 start = key->offset; 518 u64 start = key->offset;
491 u64 saved_nbytes; 519 u64 nbytes = 0;
492 struct btrfs_file_extent_item *item; 520 struct btrfs_file_extent_item *item;
493 struct inode *inode = NULL; 521 struct inode *inode = NULL;
494 unsigned long size; 522 unsigned long size;
@@ -498,10 +526,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
498 found_type = btrfs_file_extent_type(eb, item); 526 found_type = btrfs_file_extent_type(eb, item);
499 527
500 if (found_type == BTRFS_FILE_EXTENT_REG || 528 if (found_type == BTRFS_FILE_EXTENT_REG ||
501 found_type == BTRFS_FILE_EXTENT_PREALLOC) 529 found_type == BTRFS_FILE_EXTENT_PREALLOC) {
502 extent_end = start + btrfs_file_extent_num_bytes(eb, item); 530 nbytes = btrfs_file_extent_num_bytes(eb, item);
503 else if (found_type == BTRFS_FILE_EXTENT_INLINE) { 531 extent_end = start + nbytes;
532
533 /*
534 * We don't add to the inodes nbytes if we are prealloc or a
535 * hole.
536 */
537 if (btrfs_file_extent_disk_bytenr(eb, item) == 0)
538 nbytes = 0;
539 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
504 size = btrfs_file_extent_inline_len(eb, item); 540 size = btrfs_file_extent_inline_len(eb, item);
541 nbytes = btrfs_file_extent_ram_bytes(eb, item);
505 extent_end = (start + size + mask) & ~mask; 542 extent_end = (start + size + mask) & ~mask;
506 } else { 543 } else {
507 ret = 0; 544 ret = 0;
@@ -550,7 +587,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
550 } 587 }
551 btrfs_release_path(path); 588 btrfs_release_path(path);
552 589
553 saved_nbytes = inode_get_bytes(inode);
554 /* drop any overlapping extents */ 590 /* drop any overlapping extents */
555 ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); 591 ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);
556 BUG_ON(ret); 592 BUG_ON(ret);
@@ -637,7 +673,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
637 BUG_ON(ret); 673 BUG_ON(ret);
638 } 674 }
639 675
640 inode_set_bytes(inode, saved_nbytes); 676 inode_add_bytes(inode, nbytes);
641 ret = btrfs_update_inode(trans, root, inode); 677 ret = btrfs_update_inode(trans, root, inode);
642out: 678out:
643 if (inode) 679 if (inode)