summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-14 13:52:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-14 13:52:54 -0400
commit3792a64fdeeb9cab56c22695aaeb0624f1b295b4 (patch)
tree6867fa61e0a61e87f3ec273248339dd72666afd2 /fs
parent3c91930f0cbd54d522d8844b221c36199a2dc11e (diff)
parent4bc4bee4595662d8bff92180d5c32e3313a704b0 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull one more btrfs fix from Chris Mason: "This has a recent fix from Josef for our tree log replay code. It fixes problems where the inode counter for the number of bytes in the file wasn't getting updated properly during fsync replay. The commit did get rebased this morning, but it was only to clean up the subject line. The code hasn't changed." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: Btrfs: make sure nbytes are right after log replay
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 451fad96ecd1..ef96381569a4 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -317,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
317 unsigned long src_ptr; 317 unsigned long src_ptr;
318 unsigned long dst_ptr; 318 unsigned long dst_ptr;
319 int overwrite_root = 0; 319 int overwrite_root = 0;
320 bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
320 321
321 if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) 322 if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
322 overwrite_root = 1; 323 overwrite_root = 1;
@@ -326,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
326 327
327 /* look for the key in the destination tree */ 328 /* look for the key in the destination tree */
328 ret = btrfs_search_slot(NULL, root, key, path, 0, 0); 329 ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
330 if (ret < 0)
331 return ret;
332
329 if (ret == 0) { 333 if (ret == 0) {
330 char *src_copy; 334 char *src_copy;
331 char *dst_copy; 335 char *dst_copy;
@@ -367,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
367 return 0; 371 return 0;
368 } 372 }
369 373
374 /*
375 * We need to load the old nbytes into the inode so when we
376 * replay the extents we've logged we get the right nbytes.
377 */
378 if (inode_item) {
379 struct btrfs_inode_item *item;
380 u64 nbytes;
381
382 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
383 struct btrfs_inode_item);
384 nbytes = btrfs_inode_nbytes(path->nodes[0], item);
385 item = btrfs_item_ptr(eb, slot,
386 struct btrfs_inode_item);
387 btrfs_set_inode_nbytes(eb, item, nbytes);
388 }
389 } else if (inode_item) {
390 struct btrfs_inode_item *item;
391
392 /*
393 * New inode, set nbytes to 0 so that the nbytes comes out
394 * properly when we replay the extents.
395 */
396 item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item);
397 btrfs_set_inode_nbytes(eb, item, 0);
370 } 398 }
371insert: 399insert:
372 btrfs_release_path(path); 400 btrfs_release_path(path);
@@ -486,7 +514,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
486 int found_type; 514 int found_type;
487 u64 extent_end; 515 u64 extent_end;
488 u64 start = key->offset; 516 u64 start = key->offset;
489 u64 saved_nbytes; 517 u64 nbytes = 0;
490 struct btrfs_file_extent_item *item; 518 struct btrfs_file_extent_item *item;
491 struct inode *inode = NULL; 519 struct inode *inode = NULL;
492 unsigned long size; 520 unsigned long size;
@@ -496,10 +524,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
496 found_type = btrfs_file_extent_type(eb, item); 524 found_type = btrfs_file_extent_type(eb, item);
497 525
498 if (found_type == BTRFS_FILE_EXTENT_REG || 526 if (found_type == BTRFS_FILE_EXTENT_REG ||
499 found_type == BTRFS_FILE_EXTENT_PREALLOC) 527 found_type == BTRFS_FILE_EXTENT_PREALLOC) {
500 extent_end = start + btrfs_file_extent_num_bytes(eb, item); 528 nbytes = btrfs_file_extent_num_bytes(eb, item);
501 else if (found_type == BTRFS_FILE_EXTENT_INLINE) { 529 extent_end = start + nbytes;
530
531 /*
532 * We don't add to the inodes nbytes if we are prealloc or a
533 * hole.
534 */
535 if (btrfs_file_extent_disk_bytenr(eb, item) == 0)
536 nbytes = 0;
537 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
502 size = btrfs_file_extent_inline_len(eb, item); 538 size = btrfs_file_extent_inline_len(eb, item);
539 nbytes = btrfs_file_extent_ram_bytes(eb, item);
503 extent_end = ALIGN(start + size, root->sectorsize); 540 extent_end = ALIGN(start + size, root->sectorsize);
504 } else { 541 } else {
505 ret = 0; 542 ret = 0;
@@ -548,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
548 } 585 }
549 btrfs_release_path(path); 586 btrfs_release_path(path);
550 587
551 saved_nbytes = inode_get_bytes(inode);
552 /* drop any overlapping extents */ 588 /* drop any overlapping extents */
553 ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); 589 ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);
554 BUG_ON(ret); 590 BUG_ON(ret);
@@ -635,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
635 BUG_ON(ret); 671 BUG_ON(ret);
636 } 672 }
637 673
638 inode_set_bytes(inode, saved_nbytes); 674 inode_add_bytes(inode, nbytes);
639 ret = btrfs_update_inode(trans, root, inode); 675 ret = btrfs_update_inode(trans, root, inode);
640out: 676out:
641 if (inode) 677 if (inode)