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
>> >>
>>
next prev parent 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