| From 8e138e0d92c6c9d3d481674fb14e3439b495be37 Mon Sep 17 00:00:00 2001 |
| From: Josef Bacik <jbacik@fb.com> |
| Date: Fri, 17 Nov 2017 14:50:46 -0500 |
| Subject: btrfs: clear space cache inode generation always |
| |
| From: Josef Bacik <jbacik@fb.com> |
| |
| commit 8e138e0d92c6c9d3d481674fb14e3439b495be37 upstream. |
| |
| 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. |
| |
| Signed-off-by: Josef Bacik <jbacik@fb.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/extent-tree.c | 14 +++++++------- |
| 1 file changed, 7 insertions(+), 7 deletions(-) |
| |
| --- a/fs/btrfs/extent-tree.c |
| +++ b/fs/btrfs/extent-tree.c |
| @@ -3361,13 +3361,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 |
| @@ -3391,6 +3384,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); |