public inbox for linux-raid@vger.kernel.org
 help / color / mirror / Atom feed
From: Su Yue <l@damenly.org>
To: Xiao Ni <xni@redhat.com>
Cc: Su Yue <glass.su@suse.com>,
	 linux-raid@vger.kernel.org, song@kernel.org,
	 linan122@huawei.com,  yukuai@fnnas.com, heming.zhao@suse.com
Subject: Re: [PATCH v2 3/5] md/md-bitmap: add dummy bitmap ops for none to fix wrong bitmap offset
Date: Tue, 21 Apr 2026 17:21:03 +0800	[thread overview]
Message-ID: <pl3s7jpc.fsf@damenly.org> (raw)
In-Reply-To: <CALTww29y_EJq3Qkimn67cSTnL6_+Yi6Lf1LoT=JJM6YqmFTjaw@mail.gmail.com> (Xiao Ni's message of "Tue, 21 Apr 2026 15:36:09 +0800")

On Tue 21 Apr 2026 at 15:36, Xiao Ni <xni@redhat.com> wrote:

> On Tue, Apr 21, 2026 at 10:29 AM Su Yue <l@damenly.org> wrote:
>>
>> On Mon 20 Apr 2026 at 15:05, Xiao Ni <xni@redhat.com> wrote:
>>
>> > On Tue, Apr 7, 2026 at 6:27 PM Su Yue <glass.su@suse.com> 
>> > wrote:
>> >>
>> >> Before commit fb8cc3b0d9db ("md/md-bitmap: delay 
>> >> registration
>> >> of bitmap_ops until creating bitmap")
>> >> if CONFIG_MD_BITMAP is enabled, both bitmap none, internal 
>> >> and
>> >> clustered have
>> >> the sysfs file bitmap/location.
>> >>
>> >> After the commit, if bitmap is none, bitmap/location doesn't
>> >> exist anymore.
>> >> It breaks 'grow' behavior of a md array of madam with
>> >> MD_FEATURE_BITMAP_OFFSET.
>> >> Take level=mirror and metadata=1.2 as an example:
>> >>
>> >> $ mdadm  --create  /dev/md0 -f --bitmap=none 
>> >> --raid-devices=2
>> >> --level=mirror \
>> >>   --metadata=1.2 /dev/vdd /dev/vde
>> >> $ mdadm --grow /dev/md0 --bitmap=internal
>> >> $ cat /sys/block/md0/md/bitmap/location
>> >> Before:+8
>> >> After: +2
>> >>
>> >> While growing bitmap from none to internal, clustered and
>> >> llbitmap,
>> >> mdadm/Grow.c:Grow_addbitmap() tries to detect 
>> >> bitmap/location
>> >> first.
>> >> 1)If bitmap/location exists, it sets bitmap/location after
>> >> getinfo_super().
>> >> 2)If bitmap/location doesn't exist, mdadm just calls
>> >> md_set_array_info() then
>> >> mddev->bitmap_info.default_offset will be used.
>> >> Situation can be worse if growing none to clustered, bitmap
>> >> offset of the node
>> >> calling `madm --grow` will be changed but the other node are
>> >> reading bitmap sb from
>> >> the old location.
>> >>
>> >> Here introducing a dummy bitmap_operations for 
>> >> ID_BITMAP_NONE
>> >> to restore sysfs
>> >> file bitmap/location for ID_BITMAP_NONE and ID_BITMAP.
>> >> location_store() now calls md_bitmap_(create|destroy) with
>> >> false sysfs parameter then
>> >> (add,remove)_internal_bitmap() will be called to manage 
>> >> sysfs
>> >> entries.
>> >>
>> >> Fixes: fb8cc3b0d9db ("md/md-bitmap: delay registration of
>> >> bitmap_ops until creating bitmap")
>> >> Suggested-by: Yu Kuai <yukuai@fnnas.com>
>> >> Signed-off-by: Su Yue <glass.su@suse.com>
>> >> ---
>> >>  drivers/md/md-bitmap.c   | 116
>> >>  ++++++++++++++++++++++++++++++++++++---
>> >>  drivers/md/md-bitmap.h   |   3 +
>> >>  drivers/md/md-llbitmap.c |  12 ++++
>> >>  drivers/md/md.c          |  16 +++---
>> >>  4 files changed, 130 insertions(+), 17 deletions(-)
>> >>
>> >> diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
>> >> index ac06c9647bf0..a8a176428c61 100644
>> >> --- a/drivers/md/md-bitmap.c
>> >> +++ b/drivers/md/md-bitmap.c
>> >> @@ -240,6 +240,11 @@ static bool bitmap_enabled(void *data,
>> >> bool flush)
>> >>                bitmap->storage.filemap != NULL;
>> >>  }
>> >>
>> >> +static bool dummy_bitmap_enabled(void *data, bool flush)
>> >> +{
>> >> +       return false;
>> >> +}
>> >> +
>> >>  /*
>> >>   * check a page and, if necessary, allocate it (or hijack 
>> >>   it
>> >>   if the alloc fails)
>> >>   *
>> >> @@ -2201,6 +2206,11 @@ static int bitmap_create(struct mddev
>> >> *mddev)
>> >>         return 0;
>> >>  }
>> >>
>> >> +static int dummy_bitmap_create(struct mddev *mddev)
>> >> +{
>> >> +       return 0;
>> >> +}
>> >> +
>> >>  static int bitmap_load(struct mddev *mddev)
>> >>  {
>> >>         int err = 0;
>> >> @@ -2594,6 +2604,9 @@ location_show(struct mddev *mddev, 
>> >> char
>> >> *page)
>> >>         return len;
>> >>  }
>> >>
>> >> +static int create_internal_group(struct mddev *mddev);
>> >> +static void remove_internal_group(struct mddev *mddev);
>> >> +
>> >>  static ssize_t
>> >>  location_store(struct mddev *mddev, const char *buf, size_t
>> >>  len)
>> >>  {
>> >> @@ -2618,7 +2631,8 @@ location_store(struct mddev *mddev, 
>> >> const
>> >> char *buf, size_t len)
>> >>                         goto out;
>> >>                 }
>> >>
>> >> -               md_bitmap_destroy(mddev, true);
>> >> +               md_bitmap_destroy(mddev, false);
>> >> +               remove_internal_group(mddev);
>> >>                 mddev->bitmap_info.offset = 0;
>> >>                 if (mddev->bitmap_info.file) {
>> >>                         struct file *f =
>> >>                         mddev->bitmap_info.file;
>> >> @@ -2659,14 +2673,22 @@ location_store(struct mddev *mddev,
>> >> const char *buf, size_t len)
>> >>                          */
>> >>                         mddev->bitmap_id = ID_BITMAP;
>> >>                         mddev->bitmap_info.offset = offset;
>> >> -                       rv = md_bitmap_create(mddev, true);
>> >> +                       rv = md_bitmap_create(mddev, false);
>> >>                         if (rv)
>> >>                                 goto out;
>> >>
>> >> +                       rv = create_internal_group(mddev);
>> >> +                       if (rv) {
>> >> +                               mddev->bitmap_info.offset = 
>> >> 0;
>> >> +                               bitmap_destroy(mddev);
>> >> +                               goto out;
>> >> +                       }
>> >> +
>> >>                         rv = bitmap_load(mddev);
>> >>                         if (rv) {
>> >> + 
>> >> remove_internal_group(mddev);
>> >>                                 mddev->bitmap_info.offset = 
>> >>                                 0;
>> >> -                               md_bitmap_destroy(mddev, 
>> >> true);
>> >> +                               md_bitmap_destroy(mddev,
>> >> false);
>> >>                                 goto out;
>> >>                         }
>> >>                 }
>> >> @@ -2960,8 +2982,7 @@ static struct md_sysfs_entry
>> >> max_backlog_used =
>> >>  __ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
>> >>         behind_writes_used_show, behind_writes_used_reset);
>> >>
>> >> -static struct attribute *md_bitmap_attrs[] = {
>> >> -       &bitmap_location.attr,
>> >> +static struct attribute *internal_bitmap_attrs[] = {
>> >>         &bitmap_space.attr,
>> >>         &bitmap_timeout.attr,
>> >>         &bitmap_backlog.attr,
>> >> @@ -2972,11 +2993,57 @@ static struct attribute
>> >> *md_bitmap_attrs[] = {
>> >>         NULL
>> >>  };
>> >>
>> >> -static struct attribute_group md_bitmap_group = {
>> >> +static struct attribute_group internal_bitmap_group = {
>> >>         .name = "bitmap",
>> >> -       .attrs = md_bitmap_attrs,
>> >> +       .attrs = internal_bitmap_attrs,
>> >>  };
>> >>
>> >> +/* Only necessary attrs for compatibility */
>> >> +static struct attribute *common_bitmap_attrs[] = {
>> >> +       &bitmap_location.attr,
>> >> +       NULL
>> >> +};
>> >> +
>> >> +static const struct attribute_group common_bitmap_group = {
>> >> +       .name = "bitmap",
>> >> +       .attrs = common_bitmap_attrs,
>> >> +};
>> >> +
>> >> +static int create_internal_group(struct mddev *mddev)
>> >> +{
>> >> +       /*
>> >> +        * md_bitmap_group and md_bitmap_common_group are 
>> >> using
>> >> same name
>> >> +        * 'bitmap'.
>> >> +        */
>> >> +       return sysfs_merge_group(&mddev->kobj,
>> >> &internal_bitmap_group);
>> >> +}
>> >> +
>> >> +static void remove_internal_group(struct mddev *mddev)
>> >> +{
>> >> +       sysfs_unmerge_group(&mddev->kobj,
>> >> &internal_bitmap_group);
>> >> +}
>> >> +
>> >> +static int bitmap_register_groups(struct mddev *mddev)
>> >> +{
>> >> +       int ret;
>> >> +
>> >> +       ret = sysfs_create_group(&mddev->kobj,
>> >> &common_bitmap_group);
>> >> +
>> >> +       if (ret)
>> >> +               return ret;
>> >> +
>> >> +       ret = sysfs_merge_group(&mddev->kobj,
>> >> &internal_bitmap_group);
>> >> +       if (ret)
>> >> +               sysfs_remove_group(&mddev->kobj,
>> >> &common_bitmap_group);
>> >> +
>> >> +       return ret;
>> >> +}
>> >> +
>> >> +static void bitmap_unregister_groups(struct mddev *mddev)
>> >> +{
>> >> +       sysfs_unmerge_group(&mddev->kobj,
>> >> &internal_bitmap_group);
>> >> +}
>> >
>> > Hi Su
>> >
>> > bitmap_unregister_groups should also remove 
>> > common_bitmap_group,
>> > right?
>> >
>>
>> As you pasted before, mdadm:Grow.c:
>>
>> int Grow_addbitmap(char *devname, int fd, struct context *c,
>> struct shape *s)
>> {
>> ...
>>         if (array.state & (1 << MD_SB_BITMAP_PRESENT)) {
>>                 if (s->btype == BitmapNone) {
>>                         array.state &= ~(1 << 
>>                         MD_SB_BITMAP_PRESENT);
>>                         if (md_set_array_info(fd, &array) != 0) 
>>                         {
>>                                 if (array.state & (1 << 
>>                                 MD_SB_CLUSTERED))
>>                                         pr_err("failed to 
>>                                         remove clustered
>>                                         bitmap.\n");
>>                                 else
>>                                         pr_err("failed to 
>>                                         remove internal 
>>                                         bitmap.\n");
>>                                 return 1;
>>                         }
>>                         return 0;
>>                 }
>>                 pr_err("bitmap already present on %s\n", 
>>                 devname);
>>                 return 1;
>>         }
>> ...
>> }
>>
>> In case of growing from internal to none,
>> bitmap_unregister_groups() will
>> be called, if common_bitmap_group is removed, bitmap/location
>> won't exist.
>> update_array_info() is a common function used by many call 
>> paths.
>> Also
>> llbitmap is involved here. I don't want to make situation and 
>> code
>> more
>> complicated like adding more codes in update_array_info().
>
> The above mdadm codes use bitmap/location. In your patch, you 
> already
> pass false to md_bitmap_destroy in location_store. So removing
> common_bitmap_group in bitmap_unregister_groups can't affect the 
> above
> case.
>
Right. Got confusion between md_set_array_info() and 
update_array_info().

>
> But after reading your below comments. It's good to me that
> bitmap_unregister_groups doesn't remove common_bitmap_group.
>
Thanks.

--
Su
>>
>>
>> >> +
>> >>  static struct bitmap_operations bitmap_ops = {
>> >
>> > You already changed md_bitmap_group to internal_bitmap_group.
>> > It's
>> > better to change bitmap_ops to internal_bitmap_ops?
>> >
>> >>         .head = {
>> >>                 .type   = MD_BITMAP,
>> >> @@ -3018,21 +3085,52 @@ static struct bitmap_operations
>> >> bitmap_ops = {
>> >>         .set_pages              = bitmap_set_pages,
>> >>         .free                   = md_bitmap_free,
>> >>
>> >> -       .group                  = &md_bitmap_group,
>> >> +       .register_groups        = bitmap_register_groups,
>> >> +       .unregister_groups      = bitmap_unregister_groups,
>> >> +};
>> >> +
>> >> +static int none_bitmap_register_groups(struct mddev *mddev)
>> >> +{
>> >> +       return sysfs_create_group(&mddev->kobj,
>> >> &common_bitmap_group);
>> >> +}
>> >> +
>> >> +static struct bitmap_operations none_bitmap_ops = {
>> >> +       .head = {
>> >> +               .type   = MD_BITMAP,
>> >> +               .id     = ID_BITMAP_NONE,
>> >> +               .name   = "none",
>> >> +       },
>> >> +
>> >> +       .enabled                = dummy_bitmap_enabled,
>> >> +       .create                 = dummy_bitmap_create,
>> >> +       .destroy                = bitmap_destroy,
>> >> +       .load                   = bitmap_load,
>> >> +       .get_stats              = bitmap_get_stats,
>> >> +       .free                   = md_bitmap_free,
>> >> +
>> >> +       .register_groups        = 
>> >> none_bitmap_register_groups,
>> >> +       .unregister_groups      = NULL,
>> >
>> > How does bitmap/location can be deleted if array is created 
>> > with
>> > no
>> > bitmap? Can the `mdadm --stop` command get stuck?
>> >
>> No. It wont get stuck.
>>
>> I guess here your concern is the timing of removing
>> common_bitmap_group.
>> The life cycle is same as before fb8cc3b0d9db. At the time
>> llbitmap is
>> not introduced, because there is no need to switch bitmap ops, 
>> so
>> all
>> attrs of bitmap are removed in kobject_put() in
>> mddev_delayed_delete()
>> queued by mddev_put(). This is now where common_bitmap_group is
>> being removed.
>
> Thanks for the explanation.
>
> Best Regards
> Xiao
>>
>> --
>> Su
>> > Best Regards
>> > Xiao
>> >
>> >>  };
>> >>
>> >>  int md_bitmap_init(void)
>> >>  {
>> >> +       int ret;
>> >> +
>> >>         md_bitmap_wq = alloc_workqueue("md_bitmap",
>> >>         WQ_MEM_RECLAIM | WQ_UNBOUND,
>> >>                                        0);
>> >>         if (!md_bitmap_wq)
>> >>                 return -ENOMEM;
>> >>
>> >> -       return register_md_submodule(&bitmap_ops.head);
>> >> +       ret = register_md_submodule(&bitmap_ops.head);
>> >> +       if (ret)
>> >> +               return ret;
>> >> +
>> >> +       return register_md_submodule(&none_bitmap_ops.head);
>> >>  }
>> >>
>> >>  void md_bitmap_exit(void)
>> >>  {
>> >>         destroy_workqueue(md_bitmap_wq);
>> >>         unregister_md_submodule(&bitmap_ops.head);
>> >> +       unregister_md_submodule(&none_bitmap_ops.head);
>> >>  }
>> >> diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
>> >> index b42a28fa83a0..10bc6854798c 100644
>> >> --- a/drivers/md/md-bitmap.h
>> >> +++ b/drivers/md/md-bitmap.h
>> >> @@ -125,6 +125,9 @@ struct bitmap_operations {
>> >>         void (*set_pages)(void *data, unsigned long pages);
>> >>         void (*free)(void *data);
>> >>
>> >> +       int (*register_groups)(struct mddev *mddev);
>> >> +       void (*unregister_groups)(struct mddev *mddev);
>> >> +
>> >>         struct attribute_group *group;
>> >>  };
>> >>
>> >> diff --git a/drivers/md/md-llbitmap.c
>> >> b/drivers/md/md-llbitmap.c
>> >> index bf398d7476b3..9b3ea4f1d268 100644
>> >> --- a/drivers/md/md-llbitmap.c
>> >> +++ b/drivers/md/md-llbitmap.c
>> >> @@ -1561,6 +1561,16 @@ static struct attribute_group
>> >> md_llbitmap_group = {
>> >>         .attrs = md_llbitmap_attrs,
>> >>  };
>> >>
>> >> +static int llbitmap_register_groups(struct mddev *mddev)
>> >> +{
>> >> +       return sysfs_create_group(&mddev->kobj,
>> >> &md_llbitmap_group);
>> >> +}
>> >> +
>> >> +static void llbitmap_unregister_groups(struct mddev *mddev)
>> >> +{
>> >> +       sysfs_remove_group(&mddev->kobj, 
>> >> &md_llbitmap_group);
>> >> +}
>> >> +
>> >>  static struct bitmap_operations llbitmap_ops = {
>> >>         .head = {
>> >>                 .type   = MD_BITMAP,
>> >> @@ -1597,6 +1607,8 @@ static struct bitmap_operations
>> >> llbitmap_ops = {
>> >>         .dirty_bits             = llbitmap_dirty_bits,
>> >>         .write_all              = llbitmap_write_all,
>> >>
>> >> +       .register_groups        = llbitmap_register_groups,
>> >> +       .unregister_groups      = 
>> >> llbitmap_unregister_groups,
>> >>         .group                  = &md_llbitmap_group,
>> >>  };
>> >>
>> >> diff --git a/drivers/md/md.c b/drivers/md/md.c
>> >> index d3c8f77b4fe3..55a95b227b83 100644
>> >> --- a/drivers/md/md.c
>> >> +++ b/drivers/md/md.c
>> >> @@ -683,8 +683,7 @@ static bool mddev_set_bitmap_ops(struct
>> >> mddev *mddev, bool create_sysfs)
>> >>         struct bitmap_operations *old = mddev->bitmap_ops;
>> >>         struct md_submodule_head *head;
>> >>
>> >> -       if (mddev->bitmap_id == ID_BITMAP_NONE ||
>> >> -           (old && old->head.id == mddev->bitmap_id))
>> >> +       if (old && old->head.id == mddev->bitmap_id)
>> >>                 return true;
>> >>
>> >>         xa_lock(&md_submodule);
>> >> @@ -703,8 +702,8 @@ static bool mddev_set_bitmap_ops(struct
>> >> mddev *mddev, bool create_sysfs)
>> >>         mddev->bitmap_ops = (void *)head;
>> >>         xa_unlock(&md_submodule);
>> >>
>> >> -       if (create_sysfs && !mddev_is_dm(mddev) &&
>> >> mddev->bitmap_ops->group) {
>> >> -               if (sysfs_create_group(&mddev->kobj,
>> >> mddev->bitmap_ops->group))
>> >> +       if (create_sysfs && !mddev_is_dm(mddev) &&
>> >> mddev->bitmap_ops->register_groups) {
>> >> +               if 
>> >> (mddev->bitmap_ops->register_groups(mddev))
>> >>                         pr_warn("md: cannot register extra
>> >>                         bitmap attributes for %s\n",
>> >>                                 mdname(mddev));
>> >>                 else
>> >> @@ -724,8 +723,8 @@ static bool mddev_set_bitmap_ops(struct
>> >> mddev *mddev, bool create_sysfs)
>> >>  static void mddev_clear_bitmap_ops(struct mddev *mddev, 
>> >>  bool
>> >>  remove_sysfs)
>> >>  {
>> >>         if (remove_sysfs && !mddev_is_dm(mddev) &&
>> >>         mddev->bitmap_ops &&
>> >> -           mddev->bitmap_ops->group)
>> >> -               sysfs_remove_group(&mddev->kobj,
>> >> mddev->bitmap_ops->group);
>> >> +           mddev->bitmap_ops->unregister_groups)
>> >> +               mddev->bitmap_ops->unregister_groups(mddev);
>> >>
>> >>         mddev->bitmap_ops = NULL;
>> >>  }
>> >> @@ -6610,8 +6609,9 @@ int md_run(struct mddev *mddev)
>> >>                         (unsigned long 
>> >>                         long)pers->size(mddev,
>> >>                         0, 0) / 2);
>> >>                 err = -EINVAL;
>> >>         }
>> >> -       if (err == 0 && pers->sync_request &&
>> >> -           (mddev->bitmap_info.file ||
>> >> mddev->bitmap_info.offset)) {
>> >> +       if (err == 0 && pers->sync_request) {
>> >> +               if (mddev->bitmap_info.offset == 0)
>> >> +                       mddev->bitmap_id = ID_BITMAP_NONE;
>> >>                 err = md_bitmap_create(mddev, true);
>> >>                 if (err)
>> >>                         pr_warn("%s: failed to create bitmap
>> >>                         (%d)\n",
>> >> --
>> >> 2.53.0
>> >>
>>

  reply	other threads:[~2026-04-21  9:26 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-07 10:26 [PATCH v2 0/5] md: bitmap grow fixes Su Yue
2026-04-07 10:26 ` [PATCH v2 1/5] md/md-bitmap: call md_bitmap_create,destroy in location_store Su Yue
2026-04-13  7:47   ` Li Nan
2026-04-13 10:18     ` Su Yue
2026-04-15 10:34   ` Xiao Ni
2026-04-16 14:08     ` Su Yue
2026-04-20  5:21       ` Xiao Ni
2026-04-21  1:26         ` Su Yue
2026-04-07 10:26 ` [PATCH v2 2/5] md/md-bitmap: add an extra sysfs argument to md_bitmap_create and destroy Su Yue
2026-04-20  5:24   ` Xiao Ni
2026-04-07 10:26 ` [PATCH v2 3/5] md/md-bitmap: add dummy bitmap ops for none to fix wrong bitmap offset Su Yue
2026-04-20  7:05   ` Xiao Ni
2026-04-21  2:29     ` Su Yue
2026-04-21  7:36       ` Xiao Ni
2026-04-21  9:21         ` Su Yue [this message]
2026-04-07 10:26 ` [PATCH v2 4/5] md: skip ID_BITMAP_NONE when show available bitmap types Su Yue
2026-04-13  8:15   ` Li Nan
2026-04-13 10:23     ` Su Yue
2026-04-07 10:26 ` [PATCH v2 5/5] md/md-bitmap: remove member group from bitmap_operations Su Yue
2026-04-16 14:10 ` [PATCH v2 0/5] md: bitmap grow fixes Su Yue
2026-04-21  5:15 ` Yu Kuai
2026-04-21  5:39   ` Su Yue

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=pl3s7jpc.fsf@damenly.org \
    --to=l@damenly.org \
    --cc=glass.su@suse.com \
    --cc=heming.zhao@suse.com \
    --cc=linan122@huawei.com \
    --cc=linux-raid@vger.kernel.org \
    --cc=song@kernel.org \
    --cc=xni@redhat.com \
    --cc=yukuai@fnnas.com \
    /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