Re: [PATCH v4] btrfs: zoned: don't force read-only on transient -EAGAIN from reloc merge

Filipe Manana <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <CAL3q7H5yeNXoSBDB4g4pjMKku2k6-Vctk0uEVTd_MK=Wb1s5iA@mail.gmail.com>
On Mon, Jun 22, 2026 at 9:27 AM Johannes Thumshirn
<[email protected]> wrote:
>
> On a zoned FS, btrfs_delayed_refs_rsv_refill() returns -EAGAIN whenever
> the over-committed metadata plus the zone_unusable bytes exceeds the
> usable size in a metadata block-group to avoid heavy over-commit of
> metadata and early ENOSPC in one transaction.
>
> If this happens while doing reclaim, the transaction is getting
> aborted.
>
> Treat -EAGAIN as a soft, retryable condition in case of block-group
> reclaim.
>
> Reported-by: Damien Le Moal <[email protected]>
> Fixes: 7bcb04de982f ("btrfs: zoned: cap delayed refs metadata reservation to avoid overcommit")
> Signed-off-by: Johannes Thumshirn <[email protected]>
> ---
> Changes to v3:
> - Don't ASSERT() for zoned in case of EAGAIN in
>   btrfs_reclaim_block_group but check for zoned
>
>  fs/btrfs/block-group.c | 10 +++++++-
>  fs/btrfs/relocation.c  | 52 ++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 57 insertions(+), 5 deletions(-)
>
> diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
> index ab76a5173272..1327fd526b06 100644
> --- a/fs/btrfs/block-group.c
> +++ b/fs/btrfs/block-group.c
> @@ -2047,6 +2047,12 @@ static int btrfs_reclaim_block_group(struct btrfs_block_group *bg, int *reclaime
>
>         trace_btrfs_reclaim_block_group(bg);
>         ret = btrfs_relocate_chunk(fs_info, bg->start, false);
> +       if (btrfs_is_zoned(fs_info) && ret == -EAGAIN) {
> +               btrfs_dec_block_group_ro(bg);
> +               btrfs_debug(fs_info, "deferring reclaim of chunk %llu",
> +                           bg->start);
> +               return ret;
> +       }
>         if (ret) {
>                 btrfs_dec_block_group_ro(bg);
>                 btrfs_err(fs_info, "error relocating chunk %llu",
> @@ -2113,7 +2119,9 @@ void btrfs_reclaim_block_groups(struct btrfs_fs_info *fs_info, unsigned int limi
>                 spin_unlock(&fs_info->unused_bgs_lock);
>                 ret = btrfs_reclaim_block_group(bg, &reclaimed);
>
> -               if (ret && !READ_ONCE(space_info->periodic_reclaim))
> +               if (ret == -EAGAIN)
> +                       btrfs_link_bg_list(bg, &retry_list);
> +               else if (ret && !READ_ONCE(space_info->periodic_reclaim))
>                         btrfs_link_bg_list(bg, &retry_list);
>                 btrfs_put_block_group(bg);
>
> diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
> index 1819d49d19c3..73d9948b5382 100644
> --- a/fs/btrfs/relocation.c
> +++ b/fs/btrfs/relocation.c
> @@ -1530,6 +1530,36 @@ static void clear_reloc_root(struct btrfs_root *root)
>         clear_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state);
>  }
>
> +/* Drop the reloc trees of a relocation that is being deferred and retried */

Same comment as in v3: always add punctuation to sentences, this is
our preferred style.

> +static void abort_reloc_roots(struct reloc_control *rc, struct list_head *list)
> +{
> +       struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
> +       struct btrfs_root *reloc_root, *tmp;
> +
> +       list_for_each_entry_safe(reloc_root, tmp, list, root_list) {
> +               struct btrfs_root *root;
> +
> +               root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset,
> +                                        false);
> +               if (!IS_ERR(root)) {
> +                       if (root->reloc_root == reloc_root) {
> +                               clear_reloc_root(root);
> +                               btrfs_put_root(reloc_root);
> +                       }
> +                       btrfs_put_root(root);
> +               }
> +
> +               btrfs_set_root_refs(&reloc_root->root_item, 0);
> +               memset(&reloc_root->root_item.drop_progress, 0,
> +                      sizeof(struct btrfs_disk_key));
> +               btrfs_set_root_drop_level(&reloc_root->root_item, 0);
> +
> +               list_del_init(&reloc_root->root_list);
> +               list_add_tail(&reloc_root->reloc_dirty_list,
> +                               &rc->dirty_subvol_roots);
> +       }
> +}
> +
>  static int clean_dirty_subvols(struct reloc_control *rc)
>  {
>         struct btrfs_root *root;
> @@ -1869,8 +1899,9 @@ int prepare_to_merge(struct reloc_control *rc, int err)
>         return err;
>  }
>
> +

Same comment as in v3: stray, accidental, new line.

>  static noinline_for_stack
> -void merge_reloc_roots(struct reloc_control *rc)
> +int merge_reloc_roots(struct reloc_control *rc)
>  {
>         struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
>         struct btrfs_root *root;
> @@ -1968,7 +1999,15 @@ void merge_reloc_roots(struct reloc_control *rc)
>                 goto again;
>         }
>  out:
> -       if (ret) {
> +       if (ret == -EAGAIN) {

As pointed in v3, missing an:    && (btrfs_is_zoned(fs_info)

> +               abort_reloc_roots(rc, &reloc_roots);
> +
> +               /* new reloc root may be added */

Same comment as in v3: always capitalize the first word and add
punctuation to sentences, this is our preferred style.

Otherwise it looks fine, thanks.

> +               mutex_lock(&fs_info->reloc_mutex);
> +               list_splice_init(&rc->reloc_roots, &reloc_roots);
> +               mutex_unlock(&fs_info->reloc_mutex);
> +               abort_reloc_roots(rc, &reloc_roots);
> +       } else if (ret) {
>                 btrfs_handle_fs_error(fs_info, ret, NULL);
>                 free_reloc_roots(&reloc_roots);
>
> @@ -1994,6 +2033,7 @@ void merge_reloc_roots(struct reloc_control *rc)
>          *
>          * The remaining nodes will be cleaned up by put_reloc_control().
>          */
> +       return ret;
>  }
>
>  static void free_block_list(struct rb_root *blocks)
> @@ -3723,7 +3763,9 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
>          */
>         err = prepare_to_merge(rc, err);
>
> -       merge_reloc_roots(rc);
> +       ret = merge_reloc_roots(rc);
> +       if (ret && !err)
> +               err = ret;
>
>         rc->merge_reloc_tree = false;
>         unset_reloc_control(rc);
> @@ -5692,7 +5734,9 @@ int btrfs_recover_relocation(struct btrfs_fs_info *fs_info)
>         if (ret)
>                 goto out_unset;
>
> -       merge_reloc_roots(rc);
> +       ret = merge_reloc_roots(rc);
> +       if (ret)
> +               goto out_unset;
>
>         unset_reloc_control(rc);
>
> --
> 2.54.0
>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.