Btrfs: fix incorrect file size after shrinking truncate and fsync
[sfrench/cifs-2.6.git] / fs / btrfs / tree-log.c
index f06454a55e00cb4df0f71f03eb0013adbae1e4f4..5256cddf3a43069e68c21e909f09e84dd8f1bec6 100644 (file)
@@ -4544,6 +4544,19 @@ static int logged_inode_size(struct btrfs_root *log, struct btrfs_inode *inode,
                item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                      struct btrfs_inode_item);
                *size_ret = btrfs_inode_size(path->nodes[0], item);
+               /*
+                * If the in-memory inode's i_size is smaller then the inode
+                * size stored in the btree, return the inode's i_size, so
+                * that we get a correct inode size after replaying the log
+                * when before a power failure we had a shrinking truncate
+                * followed by addition of a new name (rename / new hard link).
+                * Otherwise return the inode size from the btree, to avoid
+                * data loss when replaying a log due to previously doing a
+                * write that expands the inode's size and logging a new name
+                * immediately after.
+                */
+               if (*size_ret > inode->vfs_inode.i_size)
+                       *size_ret = inode->vfs_inode.i_size;
        }
 
        btrfs_release_path(path);