--- /dev/null
+From 4bc4bee4595662d8bff92180d5c32e3313a704b0 Mon Sep 17 00:00:00 2001
+From: Josef Bacik <jbacik@fusionio.com>
+Date: Fri, 5 Apr 2013 20:50:09 +0000
+Subject: Btrfs: make sure nbytes are right after log replay
+
+From: Josef Bacik <jbacik@fusionio.com>
+
+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>
+
+---
+ fs/btrfs/tree-log.c | 48 ++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 42 insertions(+), 6 deletions(-)
+
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -318,6 +318,7 @@ static noinline int overwrite_item(struc
+ unsigned long src_ptr;
+ unsigned long dst_ptr;
+ int overwrite_root = 0;
++ bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
+
+ if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
+ overwrite_root = 1;
+@@ -327,6 +328,9 @@ static noinline int overwrite_item(struc
+
+ /* look for the key in the destination tree */
+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
++ if (ret < 0)
++ return ret;
++
+ if (ret == 0) {
+ char *src_copy;
+ char *dst_copy;
+@@ -368,6 +372,30 @@ static noinline int overwrite_item(struc
+ 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:
+ btrfs_release_path(path);
+@@ -488,7 +516,7 @@ static noinline int replay_one_extent(st
+ u64 mask = root->sectorsize - 1;
+ u64 extent_end;
+ u64 start = key->offset;
+- u64 saved_nbytes;
++ u64 nbytes = 0;
+ struct btrfs_file_extent_item *item;
+ struct inode *inode = NULL;
+ unsigned long size;
+@@ -498,10 +526,19 @@ static noinline int replay_one_extent(st
+ found_type = btrfs_file_extent_type(eb, item);
+
+ if (found_type == BTRFS_FILE_EXTENT_REG ||
+- found_type == BTRFS_FILE_EXTENT_PREALLOC)
+- extent_end = start + btrfs_file_extent_num_bytes(eb, item);
+- else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
++ found_type == BTRFS_FILE_EXTENT_PREALLOC) {
++ nbytes = btrfs_file_extent_num_bytes(eb, item);
++ 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);
++ nbytes = btrfs_file_extent_ram_bytes(eb, item);
+ extent_end = (start + size + mask) & ~mask;
+ } else {
+ ret = 0;
+@@ -550,7 +587,6 @@ static noinline int replay_one_extent(st
+ }
+ btrfs_release_path(path);
+
+- saved_nbytes = inode_get_bytes(inode);
+ /* drop any overlapping extents */
+ ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);
+ BUG_ON(ret);
+@@ -637,7 +673,7 @@ static noinline int replay_one_extent(st
+ BUG_ON(ret);
+ }
+
+- inode_set_bytes(inode, saved_nbytes);
++ inode_add_bytes(inode, nbytes);
+ ret = btrfs_update_inode(trans, root, inode);
+ out:
+ if (inode)