linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Nikolay Borisov <nborisov@suse.com>
To: fdmanana@kernel.org, linux-btrfs@vger.kernel.org
Subject: Re: [PATCH] Btrfs: fix access to available allocation bits when starting balance
Date: Mon, 19 Nov 2018 11:55:50 +0200	[thread overview]
Message-ID: <e9416e6f-f237-09ed-a18c-26946329a67c@suse.com> (raw)
In-Reply-To: <20181119094812.27296-1-fdmanana@kernel.org>



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);
> 

  reply	other threads:[~2018-11-19  9:55 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-19  9:48 [PATCH] Btrfs: fix access to available allocation bits when starting balance fdmanana
2018-11-19  9:55 ` Nikolay Borisov [this message]
2018-11-21 16:46 ` David Sterba

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e9416e6f-f237-09ed-a18c-26946329a67c@suse.com \
    --to=nborisov@suse.com \
    --cc=fdmanana@kernel.org \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).