Commit 4bc4bee4 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: make sure nbytes are right after log replay

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.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent d8fe29e9
...@@ -317,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, ...@@ -317,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
unsigned long src_ptr; unsigned long src_ptr;
unsigned long dst_ptr; unsigned long dst_ptr;
int overwrite_root = 0; int overwrite_root = 0;
bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
overwrite_root = 1; overwrite_root = 1;
...@@ -326,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, ...@@ -326,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
/* look for the key in the destination tree */ /* look for the key in the destination tree */
ret = btrfs_search_slot(NULL, root, key, path, 0, 0); ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
if (ret < 0)
return ret;
if (ret == 0) { if (ret == 0) {
char *src_copy; char *src_copy;
char *dst_copy; char *dst_copy;
...@@ -367,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, ...@@ -367,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
/*
* We need to load the old nbytes into the inode so when we
* replay the extents we've logged we get the right nbytes.
*/
if (inode_item) {
struct btrfs_inode_item *item;
u64 nbytes;
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_item);
nbytes = btrfs_inode_nbytes(path->nodes[0], item);
item = btrfs_item_ptr(eb, slot,
struct btrfs_inode_item);
btrfs_set_inode_nbytes(eb, item, nbytes);
}
} else if (inode_item) {
struct btrfs_inode_item *item;
/*
* New inode, set nbytes to 0 so that the nbytes comes out
* properly when we replay the extents.
*/
item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item);
btrfs_set_inode_nbytes(eb, item, 0);
} }
insert: insert:
btrfs_release_path(path); btrfs_release_path(path);
...@@ -486,7 +514,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ...@@ -486,7 +514,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
int found_type; int found_type;
u64 extent_end; u64 extent_end;
u64 start = key->offset; u64 start = key->offset;
u64 saved_nbytes; u64 nbytes = 0;
struct btrfs_file_extent_item *item; struct btrfs_file_extent_item *item;
struct inode *inode = NULL; struct inode *inode = NULL;
unsigned long size; unsigned long size;
...@@ -496,10 +524,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ...@@ -496,10 +524,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
found_type = btrfs_file_extent_type(eb, item); found_type = btrfs_file_extent_type(eb, item);
if (found_type == BTRFS_FILE_EXTENT_REG || if (found_type == BTRFS_FILE_EXTENT_REG ||
found_type == BTRFS_FILE_EXTENT_PREALLOC) found_type == BTRFS_FILE_EXTENT_PREALLOC) {
extent_end = start + btrfs_file_extent_num_bytes(eb, item); nbytes = btrfs_file_extent_num_bytes(eb, item);
else if (found_type == BTRFS_FILE_EXTENT_INLINE) { extent_end = start + nbytes;
/*
* We don't add to the inodes nbytes if we are prealloc or a
* hole.
*/
if (btrfs_file_extent_disk_bytenr(eb, item) == 0)
nbytes = 0;
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
size = btrfs_file_extent_inline_len(eb, item); size = btrfs_file_extent_inline_len(eb, item);
nbytes = btrfs_file_extent_ram_bytes(eb, item);
extent_end = ALIGN(start + size, root->sectorsize); extent_end = ALIGN(start + size, root->sectorsize);
} else { } else {
ret = 0; ret = 0;
...@@ -548,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ...@@ -548,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
} }
btrfs_release_path(path); btrfs_release_path(path);
saved_nbytes = inode_get_bytes(inode);
/* drop any overlapping extents */ /* drop any overlapping extents */
ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);
BUG_ON(ret); BUG_ON(ret);
...@@ -635,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ...@@ -635,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
} }
inode_set_bytes(inode, saved_nbytes); inode_add_bytes(inode, nbytes);
ret = btrfs_update_inode(trans, root, inode); ret = btrfs_update_inode(trans, root, inode);
out: out:
if (inode) if (inode)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment