Home Home > GIT Browse > stable
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2019-01-18 07:53:27 +0100
committerJiri Slaby <jslaby@suse.cz>2019-01-18 07:53:43 +0100
commit6ae5bfac0a05746958c3fab3b2162e7340225abb (patch)
tree0d24d90e3e01f6e77ce99d7ea6ed40bb108284fc
parent54fa491783fe43663a0e704b1abcd5c633024d65 (diff)
Btrfs: fix access to available allocation bits when starting
balance (bnc#1012628).
-rw-r--r--patches.kernel.org/4.20.3-055-Btrfs-fix-access-to-available-allocation-bits-.patch106
-rw-r--r--series.conf1
2 files changed, 107 insertions, 0 deletions
diff --git a/patches.kernel.org/4.20.3-055-Btrfs-fix-access-to-available-allocation-bits-.patch b/patches.kernel.org/4.20.3-055-Btrfs-fix-access-to-available-allocation-bits-.patch
new file mode 100644
index 0000000000..68bcfd6467
--- /dev/null
+++ b/patches.kernel.org/4.20.3-055-Btrfs-fix-access-to-available-allocation-bits-.patch
@@ -0,0 +1,106 @@
+From: Filipe Manana <fdmanana@suse.com>
+Date: Mon, 19 Nov 2018 09:48:12 +0000
+Subject: [PATCH] Btrfs: fix access to available allocation bits when starting
+ balance
+References: bnc#1012628
+Patch-mainline: 4.20.3
+Git-commit: 5a8067c0d17feb7579db0476191417b441a8996e
+
+commit 5a8067c0d17feb7579db0476191417b441a8996e upstream.
+
+The available allocation bits members from struct btrfs_fs_info are
+protected by a sequence lock, and when starting balance we access them
+incorrectly in two different ways:
+
+1) In the read sequence lock loop at btrfs_balance() we use the values we
+ read from fs_info->avail_*_alloc_bits and we can immediately do actions
+ that have side effects and can not be undone (printing a message and
+ jumping to a label). This is wrong because a retry might be needed, so
+ our actions must not have side effects and must be repeatable as long
+ as read_seqretry() returns a non-zero value. In other words, we were
+ essentially ignoring the sequence lock;
+
+2) Right below the read sequence lock loop, we were reading the values
+ from avail_metadata_alloc_bits and avail_data_alloc_bits without any
+ protection from concurrent writers, that is, reading them outside of
+ the read sequence lock critical section.
+
+So fix this by making sure we only read the available allocation bits
+while in a read sequence lock critical section and that what we do in the
+critical section is repeatable (has nothing that can not be undone) so
+that any eventual retry that is needed is handled properly.
+
+Fixes: de98ced9e743 ("Btrfs: use seqlock to protect fs_info->avail_{data, metadata, system}_alloc_bits")
+Fixes: 14506127979a ("btrfs: fix a bogus warning when converting only data or metadata")
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ fs/btrfs/volumes.c | 39 +++++++++++++++++++++++----------------
+ 1 file changed, 23 insertions(+), 16 deletions(-)
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index f435d397019e..c872adfc939e 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -3724,6 +3724,7 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
+ int ret;
+ u64 num_devices;
+ unsigned seq;
++ bool reducing_integrity;
+
+ if (btrfs_fs_closing(fs_info) ||
+ atomic_read(&fs_info->balance_pause_req) ||
+@@ -3803,24 +3804,30 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
+ !(bctl->sys.target & allowed)) ||
+ ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+ (fs_info->avail_metadata_alloc_bits & allowed) &&
+- !(bctl->meta.target & allowed))) {
+- if (bctl->flags & BTRFS_BALANCE_FORCE) {
+- btrfs_info(fs_info,
+- "balance: force reducing metadata integrity");
+- } else {
+- btrfs_err(fs_info,
+- "balance: reduces metadata integrity, use --force if you want this");
+- ret = -EINVAL;
+- goto out;
+- }
+- }
++ !(bctl->meta.target & allowed)))
++ reducing_integrity = true;
++ else
++ reducing_integrity = false;
++
++ /* if we're not converting, the target field is uninitialized */
++ meta_target = (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) ?
++ bctl->meta.target : fs_info->avail_metadata_alloc_bits;
++ data_target = (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) ?
++ bctl->data.target : fs_info->avail_data_alloc_bits;
+ } while (read_seqretry(&fs_info->profiles_lock, seq));
+
+- /* if we're not converting, the target field is uninitialized */
+- meta_target = (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) ?
+- bctl->meta.target : fs_info->avail_metadata_alloc_bits;
+- data_target = (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) ?
+- bctl->data.target : fs_info->avail_data_alloc_bits;
++ if (reducing_integrity) {
++ if (bctl->flags & BTRFS_BALANCE_FORCE) {
++ btrfs_info(fs_info,
++ "balance: force reducing metadata integrity");
++ } else {
++ btrfs_err(fs_info,
++ "balance: reduces metadata integrity, use --force if you want this");
++ ret = -EINVAL;
++ goto out;
++ }
++ }
++
+ if (btrfs_get_num_tolerated_disk_barrier_failures(meta_target) <
+ btrfs_get_num_tolerated_disk_barrier_failures(data_target)) {
+ int meta_index = btrfs_bg_flags_to_raid_index(meta_target);
+--
+2.20.1
+
diff --git a/series.conf b/series.conf
index 82e6e643d0..d5cded3ef8 100644
--- a/series.conf
+++ b/series.conf
@@ -292,6 +292,7 @@
patches.kernel.org/4.20.3-052-ext4-fix-special-inode-number-checks-in-__ext4.patch
patches.kernel.org/4.20.3-053-mm-page_mapped-don-t-assume-compound-page-is-h.patch
patches.kernel.org/4.20.3-054-sunrpc-use-after-free-in-svc_process_common.patch
+ patches.kernel.org/4.20.3-055-Btrfs-fix-access-to-available-allocation-bits-.patch
########################################################
# Build fixes that apply to the vanilla kernel too.