]> git.hungrycats.org Git - linux/commitdiff
btrfs: clear space cache inode generation always
authorJosef Bacik <jbacik@fb.com>
Fri, 17 Nov 2017 19:50:46 +0000 (14:50 -0500)
committerSasha Levin <alexander.levin@verizon.com>
Fri, 8 Dec 2017 23:01:15 +0000 (18:01 -0500)
[ Upstream commit 8e138e0d92c6c9d3d481674fb14e3439b495be37 ]

We discovered a box that had double allocations, and suspected the space
cache may be to blame.  While auditing the write out path I noticed that
if we've already setup the space cache we will just carry on.  This
means that any error we hit after cache_save_setup before we go to
actually write the cache out we won't reset the inode generation, so
whatever was already written will be considered correct, except it'll be
stale.  Fix this by _always_ resetting the generation on the block group
inode, this way we only ever have valid or invalid cache.

With this patch I was no longer able to reproduce cache corruption with
dm-log-writes and my bpf error injection tool.

Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
fs/btrfs/extent-tree.c

index 1d8b3f8c36549d63d458e22b7e35bb1ad654e81f..0fd2354dfd0a5bfdc90b7e563e92936d8a81f3fa 100644 (file)
@@ -3260,13 +3260,6 @@ again:
                goto again;
        }
 
-       /* We've already setup this transaction, go ahead and exit */
-       if (block_group->cache_generation == trans->transid &&
-           i_size_read(inode)) {
-               dcs = BTRFS_DC_SETUP;
-               goto out_put;
-       }
-
        /*
         * We want to set the generation to 0, that way if anything goes wrong
         * from here on out we know not to trust this cache when we load up next
@@ -3290,6 +3283,13 @@ again:
        }
        WARN_ON(ret);
 
+       /* We've already setup this transaction, go ahead and exit */
+       if (block_group->cache_generation == trans->transid &&
+           i_size_read(inode)) {
+               dcs = BTRFS_DC_SETUP;
+               goto out_put;
+       }
+
        if (i_size_read(inode) > 0) {
                ret = btrfs_check_trunc_cache_free_space(root,
                                        &root->fs_info->global_block_rsv);