* [PATCH] Btrfs: fix access to available allocation bits when starting balance
@ 2018-11-19 9:48 fdmanana
2018-11-19 9:55 ` Nikolay Borisov
2018-11-21 16:46 ` David Sterba
0 siblings, 2 replies; 3+ messages in thread
From: fdmanana @ 2018-11-19 9:48 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
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")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
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 f4405e430da6..223334f08530 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3712,6 +3712,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) ||
@@ -3796,24 +3797,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.11.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] Btrfs: fix access to available allocation bits when starting balance
2018-11-19 9:48 [PATCH] Btrfs: fix access to available allocation bits when starting balance fdmanana
@ 2018-11-19 9:55 ` Nikolay Borisov
2018-11-21 16:46 ` David Sterba
1 sibling, 0 replies; 3+ messages in thread
From: Nikolay Borisov @ 2018-11-19 9:55 UTC (permalink / raw)
To: fdmanana, linux-btrfs
On 19.11.18 г. 11:48 ч., fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
>
> 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")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
> ---
> 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 f4405e430da6..223334f08530 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -3712,6 +3712,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) ||
> @@ -3796,24 +3797,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);
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Btrfs: fix access to available allocation bits when starting balance
2018-11-19 9:48 [PATCH] Btrfs: fix access to available allocation bits when starting balance fdmanana
2018-11-19 9:55 ` Nikolay Borisov
@ 2018-11-21 16:46 ` David Sterba
1 sibling, 0 replies; 3+ messages in thread
From: David Sterba @ 2018-11-21 16:46 UTC (permalink / raw)
To: fdmanana; +Cc: linux-btrfs
On Mon, Nov 19, 2018 at 09:48:12AM +0000, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
>
> 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")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
Added to misc-next, thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-11-21 16:46 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-11-19 9:48 [PATCH] Btrfs: fix access to available allocation bits when starting balance fdmanana
2018-11-19 9:55 ` Nikolay Borisov
2018-11-21 16:46 ` David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).