* [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs
@ 2026-04-25 2:46 Yu Kuai
2026-04-25 2:46 ` [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling Yu Kuai
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Yu Kuai @ 2026-04-25 2:46 UTC (permalink / raw)
To: Song Liu; +Cc: glass.su, Yu Kuai, Li Nan, Xiao Ni, linux-raid, linux-kernel
mdadm --grow adds an internal bitmap by writing bitmap/location for an
array that currently has no bitmap. That requires the bitmap directory
and location attribute to exist before the classic bitmap backend is
created.
This series separates bitmap backend lifetime from bitmap sysfs lifetime,
splits the sysfs layout into common and backend-specific groups, and adds
a small "none" bitmap backend. The none backend keeps bitmap/location
available while no real bitmap is active, and the location store path can
then switch between the none backend and the classic bitmap backend
without tearing down the common bitmap sysfs directory.
Patch 1 factors bitmap creation and destruction into helpers that do not
touch sysfs registration.
Patch 2 splits the classic bitmap sysfs files into a common group and an
internal-bitmap group, and converts bitmap backend operations to use a
sysfs group array.
Patch 3 adds the none backend and uses it to restore mdadm --grow bitmap
addition through bitmap/location.
Changes since v12:
- Keep the factoring patch focused on no-sysfs bitmap lifetime helpers.
- Make bitmap operation lookup depend only on the current bitmap id
matching the installed backend.
- Trim the none backend to only the operations required by the active
call paths.
- Rework bitmap/location error handling with explicit cleanup labels.
- Restore the none backend after bitmap removal and creation/load
failures so bitmap/location stays available.
Validation:
- create a RAID1 array with --bitmap=none
- verify /sys/block/md0/md/bitmap/location exists and reports "none"
- mdadm --grow /dev/md0 --bitmap=internal
- verify location switches to "+8", mdadm reports "Intent Bitmap:
Internal", and /proc/mdstat reports a bitmap
- mdadm --grow /dev/md0 --bitmap=none
- verify location switches back to "none" and only the common location
attribute remains under md/bitmap
- repeat the internal/none switch once more
- Checked the QEMU serial log for panic, Oops, BUG, WARNING, Call Trace,
RCU stall, and hung-task patterns; none were found.
Yu Kuai (3):
md: factor bitmap creation away from sysfs handling
md/md-bitmap: split bitmap sysfs groups
md/md-bitmap: add a none backend for bitmap grow
drivers/md/md-bitmap.c | 131 +++++++++++++++++++++++++++++++++++----
drivers/md/md-bitmap.h | 2 +-
drivers/md/md-llbitmap.c | 7 ++-
drivers/md/md.c | 125 ++++++++++++++++++++++++++-----------
drivers/md/md.h | 3 +
5 files changed, 218 insertions(+), 50 deletions(-)
base-commit: c85d314b135ff569c1031f2ef8e40368bcfe72ac
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling
2026-04-25 2:46 [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
@ 2026-04-25 2:46 ` Yu Kuai
2026-04-25 8:30 ` Su Yue
2026-04-25 2:46 ` [PATCH v13 2/3] md/md-bitmap: split bitmap sysfs groups Yu Kuai
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Yu Kuai @ 2026-04-25 2:46 UTC (permalink / raw)
To: Song Liu; +Cc: glass.su, Yu Kuai, Li Nan, Xiao Ni, linux-raid, linux-kernel
Factor bitmap creation and destruction into helpers that do not touch
bitmap sysfs registration.
This prepares the bitmap sysfs rework so callers such as the sysfs
bitmap location path can create or destroy a bitmap backend without
coupling that to sysfs group lifetime management.
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
---
drivers/md/md.c | 78 +++++++++++++++++++++++++++++++------------------
1 file changed, 49 insertions(+), 29 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index ebaf47fb9de6..99aa1367c991 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -679,7 +679,25 @@ static void active_io_release(struct percpu_ref *ref)
static void no_op(struct percpu_ref *r) {}
-static bool mddev_set_bitmap_ops(struct mddev *mddev)
+static void md_bitmap_sysfs_add(struct mddev *mddev)
+{
+ if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group))
+ pr_warn("md: cannot register extra bitmap attributes for %s\n",
+ mdname(mddev));
+ else
+ /*
+ * Inform user with KOBJ_CHANGE about new bitmap
+ * attributes.
+ */
+ kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
+}
+
+static void md_bitmap_sysfs_del(struct mddev *mddev)
+{
+ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
+}
+
+static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
{
struct bitmap_operations *old = mddev->bitmap_ops;
struct md_submodule_head *head;
@@ -703,18 +721,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
mddev->bitmap_ops = (void *)head;
xa_unlock(&md_submodule);
-
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) {
- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group))
- pr_warn("md: cannot register extra bitmap attributes for %s\n",
- mdname(mddev));
- else
- /*
- * Inform user with KOBJ_CHANGE about new bitmap
- * attributes.
- */
- kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
- }
return true;
err:
@@ -722,15 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
return false;
}
-static void mddev_clear_bitmap_ops(struct mddev *mddev)
-{
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
- mddev->bitmap_ops->group)
- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
-
- mddev->bitmap_ops = NULL;
-}
-
int mddev_init(struct mddev *mddev)
{
int err = 0;
@@ -6531,7 +6528,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)
return id;
}
-static int md_bitmap_create(struct mddev *mddev)
+static int md_bitmap_create_nosysfs(struct mddev *mddev)
{
enum md_submodule_id orig_id = mddev->bitmap_id;
enum md_submodule_id sb_id;
@@ -6540,7 +6537,7 @@ static int md_bitmap_create(struct mddev *mddev)
if (mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
- if (!mddev_set_bitmap_ops(mddev))
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
return -ENOENT;
err = mddev->bitmap_ops->create(mddev);
@@ -6552,7 +6549,7 @@ static int md_bitmap_create(struct mddev *mddev)
* doesn't match, and mdadm is not the latest version to set
* bitmap_type, set bitmap_ops based on the disk version.
*/
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
sb_id = md_bitmap_get_id_from_sb(mddev);
if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
@@ -6562,27 +6559,50 @@ static int md_bitmap_create(struct mddev *mddev)
mdname(mddev), orig_id, sb_id);
mddev->bitmap_id = sb_id;
- if (!mddev_set_bitmap_ops(mddev)) {
+ if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
mddev->bitmap_id = orig_id;
return -ENOENT;
}
err = mddev->bitmap_ops->create(mddev);
if (err) {
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
mddev->bitmap_id = orig_id;
}
return err;
}
-static void md_bitmap_destroy(struct mddev *mddev)
+static int md_bitmap_create(struct mddev *mddev)
+{
+ int err;
+
+ err = md_bitmap_create_nosysfs(mddev);
+ if (err)
+ return err;
+
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group)
+ md_bitmap_sysfs_add(mddev);
+
+ return 0;
+}
+
+static void md_bitmap_destroy_nosysfs(struct mddev *mddev)
{
if (!md_bitmap_registered(mddev))
return;
mddev->bitmap_ops->destroy(mddev);
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
+}
+
+static void md_bitmap_destroy(struct mddev *mddev)
+{
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
+ mddev->bitmap_ops->group)
+ md_bitmap_sysfs_del(mddev);
+
+ md_bitmap_destroy_nosysfs(mddev);
}
int md_run(struct mddev *mddev)
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v13 2/3] md/md-bitmap: split bitmap sysfs groups
2026-04-25 2:46 [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
2026-04-25 2:46 ` [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling Yu Kuai
@ 2026-04-25 2:46 ` Yu Kuai
2026-04-25 8:36 ` Su Yue
2026-04-25 2:46 ` [PATCH v13 3/3] md/md-bitmap: add a none backend for bitmap grow Yu Kuai
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Yu Kuai @ 2026-04-25 2:46 UTC (permalink / raw)
To: Song Liu; +Cc: glass.su, Yu Kuai, Li Nan, Xiao Ni, linux-raid, linux-kernel
Split the classic bitmap sysfs files into a common bitmap group with
the location attribute and a separate internal bitmap group for the
remaining files.
At the same time, convert bitmap operations from a single sysfs group
to a sysfs group array so backends can share part of their sysfs
layout while adding backend-specific attributes separately.
Switch the bitmap sysfs helpers to use sysfs_update_groups() for the
add and update path, and remove groups in reverse order so shared named
groups are unmerged before the last group removes the directory.
Also make bitmap operation lookup depend only on the currently selected
bitmap id matching the installed backend. This prepares the lookup path
for a later registered none backend.
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
---
drivers/md/md-bitmap.c | 23 +++++++++++++++++++----
drivers/md/md-bitmap.h | 2 +-
drivers/md/md-llbitmap.c | 7 ++++++-
drivers/md/md.c | 21 ++++++++++++++-------
4 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 83378c033c72..eba649703a1c 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -2955,8 +2955,12 @@ 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[] = {
+static struct attribute *md_bitmap_common_attrs[] = {
&bitmap_location.attr,
+ NULL
+};
+
+static struct attribute *md_bitmap_internal_attrs[] = {
&bitmap_space.attr,
&bitmap_timeout.attr,
&bitmap_backlog.attr,
@@ -2967,9 +2971,20 @@ static struct attribute *md_bitmap_attrs[] = {
NULL
};
-static struct attribute_group md_bitmap_group = {
+static struct attribute_group md_bitmap_common_group = {
+ .name = "bitmap",
+ .attrs = md_bitmap_common_attrs,
+};
+
+static struct attribute_group md_bitmap_internal_group = {
.name = "bitmap",
- .attrs = md_bitmap_attrs,
+ .attrs = md_bitmap_internal_attrs,
+};
+
+static const struct attribute_group *bitmap_groups[] = {
+ &md_bitmap_common_group,
+ &md_bitmap_internal_group,
+ NULL,
};
static struct bitmap_operations bitmap_ops = {
@@ -3013,7 +3028,7 @@ static struct bitmap_operations bitmap_ops = {
.set_pages = bitmap_set_pages,
.free = md_bitmap_free,
- .group = &md_bitmap_group,
+ .groups = bitmap_groups,
};
int md_bitmap_init(void)
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
index b42a28fa83a0..214f623c7e79 100644
--- a/drivers/md/md-bitmap.h
+++ b/drivers/md/md-bitmap.h
@@ -125,7 +125,7 @@ struct bitmap_operations {
void (*set_pages)(void *data, unsigned long pages);
void (*free)(void *data);
- struct attribute_group *group;
+ const struct attribute_group **groups;
};
/* the bitmap API */
diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
index 9e7e6b1a6f15..1adc5b117821 100644
--- a/drivers/md/md-llbitmap.c
+++ b/drivers/md/md-llbitmap.c
@@ -1738,6 +1738,11 @@ static struct attribute_group md_llbitmap_group = {
.attrs = md_llbitmap_attrs,
};
+static const struct attribute_group *md_llbitmap_groups[] = {
+ &md_llbitmap_group,
+ NULL,
+};
+
static struct bitmap_operations llbitmap_ops = {
.head = {
.type = MD_BITMAP,
@@ -1774,7 +1779,7 @@ static struct bitmap_operations llbitmap_ops = {
.dirty_bits = llbitmap_dirty_bits,
.write_all = llbitmap_write_all,
- .group = &md_llbitmap_group,
+ .groups = md_llbitmap_groups,
};
int md_llbitmap_init(void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 99aa1367c991..0ef81d116191 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -681,7 +681,7 @@ static void no_op(struct percpu_ref *r) {}
static void md_bitmap_sysfs_add(struct mddev *mddev)
{
- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group))
+ if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups))
pr_warn("md: cannot register extra bitmap attributes for %s\n",
mdname(mddev));
else
@@ -694,16 +694,23 @@ static void md_bitmap_sysfs_add(struct mddev *mddev)
static void md_bitmap_sysfs_del(struct mddev *mddev)
{
- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
+ int nr_groups = 0;
+
+ for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++)
+ ;
+
+ while (--nr_groups >= 1)
+ sysfs_unmerge_group(&mddev->kobj,
+ mddev->bitmap_ops->groups[nr_groups]);
+ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]);
}
static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
{
- 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 (mddev->bitmap_ops &&
+ mddev->bitmap_ops->head.id == mddev->bitmap_id)
return true;
xa_lock(&md_submodule);
@@ -6581,7 +6588,7 @@ static int md_bitmap_create(struct mddev *mddev)
if (err)
return err;
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group)
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
md_bitmap_sysfs_add(mddev);
return 0;
@@ -6599,7 +6606,7 @@ static void md_bitmap_destroy_nosysfs(struct mddev *mddev)
static void md_bitmap_destroy(struct mddev *mddev)
{
if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
- mddev->bitmap_ops->group)
+ mddev->bitmap_ops->groups)
md_bitmap_sysfs_del(mddev);
md_bitmap_destroy_nosysfs(mddev);
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v13 3/3] md/md-bitmap: add a none backend for bitmap grow
2026-04-25 2:46 [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
2026-04-25 2:46 ` [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling Yu Kuai
2026-04-25 2:46 ` [PATCH v13 2/3] md/md-bitmap: split bitmap sysfs groups Yu Kuai
@ 2026-04-25 2:46 ` Yu Kuai
2026-04-25 8:39 ` Su Yue
2026-04-25 2:49 ` [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
2026-04-25 8:41 ` Su Yue
4 siblings, 1 reply; 9+ messages in thread
From: Yu Kuai @ 2026-04-25 2:46 UTC (permalink / raw)
To: Song Liu; +Cc: glass.su, Yu Kuai, Li Nan, Xiao Ni, linux-raid, linux-kernel
Add a real none bitmap backend that exposes the common bitmap sysfs
group and use it to keep bitmap/location available when an array has no
bitmap.
Then switch the bitmap location sysfs path to move only between none
and the classic bitmap backend, using the no-sysfs bitmap helpers while
merging or unmerging the internal bitmap sysfs group.
This restores mdadm --grow bitmap addition through bitmap/location.
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
---
drivers/md/md-bitmap.c | 108 ++++++++++++++++++++++++++++++++++++++---
drivers/md/md.c | 42 +++++++++++++---
drivers/md/md.h | 3 ++
3 files changed, 137 insertions(+), 16 deletions(-)
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index eba649703a1c..028b9ca8ce52 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -216,6 +216,7 @@ struct bitmap {
};
static struct workqueue_struct *md_bitmap_wq;
+static struct attribute_group md_bitmap_internal_group;
static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks,
int chunksize, bool init);
@@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)
return __bitmap_resize(bitmap, blocks, chunksize, false);
}
+static bool bitmap_none_enabled(void *data, bool flush)
+{
+ return false;
+}
+
+static int bitmap_none_create(struct mddev *mddev)
+{
+ return 0;
+}
+
+static int bitmap_none_load(struct mddev *mddev)
+{
+ return 0;
+}
+
+static void bitmap_none_destroy(struct mddev *mddev)
+{
+}
+
+static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats)
+{
+ return -ENOENT;
+}
+
static ssize_t
location_show(struct mddev *mddev, char *page)
{
@@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
goto out;
}
- bitmap_destroy(mddev);
+ sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group);
+ md_bitmap_destroy_nosysfs(mddev);
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ goto none_err;
mddev->bitmap_info.offset = 0;
if (mddev->bitmap_info.file) {
struct file *f = mddev->bitmap_info.file;
@@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
}
mddev->bitmap_info.offset = offset;
- rv = bitmap_create(mddev);
+ md_bitmap_destroy_nosysfs(mddev);
+ mddev->bitmap_id = ID_BITMAP;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ goto bitmap_err;
+
+ rv = md_bitmap_create_nosysfs(mddev);
if (rv)
- goto out;
+ goto create_err;
- rv = bitmap_load(mddev);
+ rv = mddev->bitmap_ops->load(mddev);
if (rv) {
mddev->bitmap_info.offset = 0;
- bitmap_destroy(mddev);
- goto out;
+ goto load_err;
}
+
+ rv = sysfs_merge_group(&mddev->kobj,
+ &md_bitmap_internal_group);
+ if (rv)
+ goto merge_err;
}
}
if (!mddev->external) {
@@ -2679,6 +2717,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
if (rv)
return rv;
return len;
+
+merge_err:
+ mddev->bitmap_info.offset = 0;
+load_err:
+ md_bitmap_destroy_nosysfs(mddev);
+create_err:
+ mddev->bitmap_info.offset = 0;
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ rv = -ENOENT;
+ goto out;
+bitmap_err:
+ rv = -ENOENT;
+none_err:
+ mddev->bitmap_info.offset = 0;
+ goto out;
}
static struct md_sysfs_entry bitmap_location =
@@ -2987,6 +3041,27 @@ static const struct attribute_group *bitmap_groups[] = {
NULL,
};
+static const struct attribute_group *bitmap_none_groups[] = {
+ &md_bitmap_common_group,
+ NULL,
+};
+
+static struct bitmap_operations bitmap_none_ops = {
+ .head = {
+ .type = MD_BITMAP,
+ .id = ID_BITMAP_NONE,
+ .name = "none",
+ },
+
+ .enabled = bitmap_none_enabled,
+ .create = bitmap_none_create,
+ .load = bitmap_none_load,
+ .destroy = bitmap_none_destroy,
+ .get_stats = bitmap_none_get_stats,
+
+ .groups = bitmap_none_groups,
+};
+
static struct bitmap_operations bitmap_ops = {
.head = {
.type = MD_BITMAP,
@@ -3033,16 +3108,33 @@ static struct bitmap_operations bitmap_ops = {
int md_bitmap_init(void)
{
+ int err;
+
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);
+ err = register_md_submodule(&bitmap_none_ops.head);
+ if (err)
+ goto err_wq;
+
+ err = register_md_submodule(&bitmap_ops.head);
+ if (err)
+ goto err_none;
+
+ return 0;
+
+err_none:
+ unregister_md_submodule(&bitmap_none_ops.head);
+err_wq:
+ destroy_workqueue(md_bitmap_wq);
+ return err;
}
void md_bitmap_exit(void)
{
- destroy_workqueue(md_bitmap_wq);
unregister_md_submodule(&bitmap_ops.head);
+ unregister_md_submodule(&bitmap_none_ops.head);
+ destroy_workqueue(md_bitmap_wq);
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0ef81d116191..7937b927d923 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -705,7 +705,7 @@ static void md_bitmap_sysfs_del(struct mddev *mddev)
sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]);
}
-static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
+bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
{
struct md_submodule_head *head;
@@ -4275,7 +4275,7 @@ bitmap_type_show(struct mddev *mddev, char *page)
xa_lock(&md_submodule);
xa_for_each(&md_submodule, i, head) {
- if (head->type != MD_BITMAP)
+ if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE)
continue;
if (mddev->bitmap_id == head->id)
@@ -6535,7 +6535,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)
return id;
}
-static int md_bitmap_create_nosysfs(struct mddev *mddev)
+int md_bitmap_create_nosysfs(struct mddev *mddev)
{
enum md_submodule_id orig_id = mddev->bitmap_id;
enum md_submodule_id sb_id;
@@ -6544,8 +6544,10 @@ static int md_bitmap_create_nosysfs(struct mddev *mddev)
if (mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
- if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
+ mddev->bitmap_id = orig_id;
return -ENOENT;
+ }
err = mddev->bitmap_ops->create(mddev);
if (!err)
@@ -6559,8 +6561,10 @@ static int md_bitmap_create_nosysfs(struct mddev *mddev)
mddev->bitmap_ops = NULL;
sb_id = md_bitmap_get_id_from_sb(mddev);
- if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
+ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) {
+ mddev->bitmap_id = orig_id;
return err;
+ }
pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n",
mdname(mddev), orig_id, sb_id);
@@ -6594,7 +6598,7 @@ static int md_bitmap_create(struct mddev *mddev)
return 0;
}
-static void md_bitmap_destroy_nosysfs(struct mddev *mddev)
+void md_bitmap_destroy_nosysfs(struct mddev *mddev)
{
if (!md_bitmap_registered(mddev))
return;
@@ -6612,6 +6616,16 @@ static void md_bitmap_destroy(struct mddev *mddev)
md_bitmap_destroy_nosysfs(mddev);
}
+static void md_bitmap_set_none(struct mddev *mddev)
+{
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ return;
+
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_add(mddev);
+}
+
int md_run(struct mddev *mddev)
{
int err;
@@ -6821,6 +6835,10 @@ int md_run(struct mddev *mddev)
if (mddev->sb_flags)
md_update_sb(mddev, 0);
+ if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
+ !mddev->bitmap_info.offset)
+ md_bitmap_set_none(mddev);
+
md_new_event();
return 0;
@@ -7766,7 +7784,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
{
int err = 0;
- if (!md_bitmap_registered(mddev))
+ if (!md_bitmap_registered(mddev) ||
+ mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
if (mddev->pers) {
@@ -7831,10 +7850,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (err) {
md_bitmap_destroy(mddev);
+ md_bitmap_set_none(mddev);
fd = -1;
}
} else if (fd < 0) {
md_bitmap_destroy(mddev);
+ md_bitmap_set_none(mddev);
}
}
@@ -8141,12 +8162,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
mddev->bitmap_info.default_offset;
mddev->bitmap_info.space =
mddev->bitmap_info.default_space;
+ mddev->bitmap_id = ID_BITMAP;
rv = md_bitmap_create(mddev);
if (!rv)
rv = mddev->bitmap_ops->load(mddev);
- if (rv)
+ if (rv) {
md_bitmap_destroy(mddev);
+ mddev->bitmap_info.offset = 0;
+ md_bitmap_set_none(mddev);
+ }
} else {
struct md_bitmap_stats stats;
@@ -8174,6 +8199,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
}
md_bitmap_destroy(mddev);
mddev->bitmap_info.offset = 0;
+ md_bitmap_set_none(mddev);
}
}
md_update_sb(mddev, 1);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index d3d4e2150dc8..52c378086046 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -934,6 +934,9 @@ extern void md_allow_write(struct mddev *mddev);
extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(struct mddev *mddev);
+bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev);
+int md_bitmap_create_nosysfs(struct mddev *mddev);
+void md_bitmap_destroy_nosysfs(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs
2026-04-25 2:46 [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
` (2 preceding siblings ...)
2026-04-25 2:46 ` [PATCH v13 3/3] md/md-bitmap: add a none backend for bitmap grow Yu Kuai
@ 2026-04-25 2:49 ` Yu Kuai
2026-04-25 8:41 ` Su Yue
4 siblings, 0 replies; 9+ messages in thread
From: Yu Kuai @ 2026-04-25 2:49 UTC (permalink / raw)
To: Song Liu; +Cc: glass.su, Li Nan, Xiao Ni, linux-raid, linux-kernel, yukuai
Hi,
Please just ignore the v13, it's local version by ai that I forgot to remove.
在 2026/4/25 10:46, Yu Kuai 写道:
> mdadm --grow adds an internal bitmap by writing bitmap/location for an
> array that currently has no bitmap. That requires the bitmap directory
> and location attribute to exist before the classic bitmap backend is
> created.
>
> This series separates bitmap backend lifetime from bitmap sysfs lifetime,
> splits the sysfs layout into common and backend-specific groups, and adds
> a small "none" bitmap backend. The none backend keeps bitmap/location
> available while no real bitmap is active, and the location store path can
> then switch between the none backend and the classic bitmap backend
> without tearing down the common bitmap sysfs directory.
>
> Patch 1 factors bitmap creation and destruction into helpers that do not
> touch sysfs registration.
>
> Patch 2 splits the classic bitmap sysfs files into a common group and an
> internal-bitmap group, and converts bitmap backend operations to use a
> sysfs group array.
>
> Patch 3 adds the none backend and uses it to restore mdadm --grow bitmap
> addition through bitmap/location.
>
> Changes since v12:
> - Keep the factoring patch focused on no-sysfs bitmap lifetime helpers.
> - Make bitmap operation lookup depend only on the current bitmap id
> matching the installed backend.
> - Trim the none backend to only the operations required by the active
> call paths.
> - Rework bitmap/location error handling with explicit cleanup labels.
> - Restore the none backend after bitmap removal and creation/load
> failures so bitmap/location stays available.
>
> Validation:
> - create a RAID1 array with --bitmap=none
> - verify /sys/block/md0/md/bitmap/location exists and reports "none"
> - mdadm --grow /dev/md0 --bitmap=internal
> - verify location switches to "+8", mdadm reports "Intent Bitmap:
> Internal", and /proc/mdstat reports a bitmap
> - mdadm --grow /dev/md0 --bitmap=none
> - verify location switches back to "none" and only the common location
> attribute remains under md/bitmap
> - repeat the internal/none switch once more
> - Checked the QEMU serial log for panic, Oops, BUG, WARNING, Call Trace,
> RCU stall, and hung-task patterns; none were found.
>
> Yu Kuai (3):
> md: factor bitmap creation away from sysfs handling
> md/md-bitmap: split bitmap sysfs groups
> md/md-bitmap: add a none backend for bitmap grow
>
> drivers/md/md-bitmap.c | 131 +++++++++++++++++++++++++++++++++++----
> drivers/md/md-bitmap.h | 2 +-
> drivers/md/md-llbitmap.c | 7 ++-
> drivers/md/md.c | 125 ++++++++++++++++++++++++++-----------
> drivers/md/md.h | 3 +
> 5 files changed, 218 insertions(+), 50 deletions(-)
>
> base-commit: c85d314b135ff569c1031f2ef8e40368bcfe72ac
--
Thansk,
Kuai
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling
2026-04-25 2:46 ` [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling Yu Kuai
@ 2026-04-25 8:30 ` Su Yue
0 siblings, 0 replies; 9+ messages in thread
From: Su Yue @ 2026-04-25 8:30 UTC (permalink / raw)
To: Yu Kuai; +Cc: Song Liu, glass.su, Li Nan, Xiao Ni, linux-raid, linux-kernel
On Sat 25 Apr 2026 at 10:46, Yu Kuai <yukuai@fnnas.com> wrote:
> Factor bitmap creation and destruction into helpers that do not
> touch
> bitmap sysfs registration.
>
> This prepares the bitmap sysfs rework so callers such as the
> sysfs
> bitmap location path can create or destroy a bitmap backend
> without
> coupling that to sysfs group lifetime management.
>
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
>
Reviewed-by: Su Yue <glass.su@suse.com>
> ---
> drivers/md/md.c | 78
> +++++++++++++++++++++++++++++++------------------
> 1 file changed, 49 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index ebaf47fb9de6..99aa1367c991 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -679,7 +679,25 @@ static void active_io_release(struct
> percpu_ref *ref)
>
> static void no_op(struct percpu_ref *r) {}
>
> -static bool mddev_set_bitmap_ops(struct mddev *mddev)
> +static void md_bitmap_sysfs_add(struct mddev *mddev)
> +{
> + if (sysfs_create_group(&mddev->kobj,
> mddev->bitmap_ops->group))
> + pr_warn("md: cannot register extra bitmap attributes for
> %s\n",
> + mdname(mddev));
> + else
> + /*
> + * Inform user with KOBJ_CHANGE about new bitmap
> + * attributes.
> + */
> + kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
> +}
> +
> +static void md_bitmap_sysfs_del(struct mddev *mddev)
> +{
> + sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
> +}
> +
> +static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
> {
> struct bitmap_operations *old = mddev->bitmap_ops;
> struct md_submodule_head *head;
> @@ -703,18 +721,6 @@ static bool mddev_set_bitmap_ops(struct
> mddev *mddev)
>
> mddev->bitmap_ops = (void *)head;
> xa_unlock(&md_submodule);
> -
> - if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) {
> - if (sysfs_create_group(&mddev->kobj,
> mddev->bitmap_ops->group))
> - pr_warn("md: cannot register extra bitmap attributes
> for %s\n",
> - mdname(mddev));
> - else
> - /*
> - * Inform user with KOBJ_CHANGE about new bitmap
> - * attributes.
> - */
> - kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
> - }
> return true;
>
> err:
> @@ -722,15 +728,6 @@ static bool mddev_set_bitmap_ops(struct
> mddev *mddev)
> return false;
> }
>
> -static void mddev_clear_bitmap_ops(struct mddev *mddev)
> -{
> - if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
> - mddev->bitmap_ops->group)
> - sysfs_remove_group(&mddev->kobj,
> mddev->bitmap_ops->group);
> -
> - mddev->bitmap_ops = NULL;
> -}
> -
> int mddev_init(struct mddev *mddev)
> {
> int err = 0;
> @@ -6531,7 +6528,7 @@ static enum md_submodule_id
> md_bitmap_get_id_from_sb(struct mddev *mddev)
> return id;
> }
>
> -static int md_bitmap_create(struct mddev *mddev)
> +static int md_bitmap_create_nosysfs(struct mddev *mddev)
> {
> enum md_submodule_id orig_id = mddev->bitmap_id;
> enum md_submodule_id sb_id;
> @@ -6540,7 +6537,7 @@ static int md_bitmap_create(struct mddev
> *mddev)
> if (mddev->bitmap_id == ID_BITMAP_NONE)
> return -EINVAL;
>
> - if (!mddev_set_bitmap_ops(mddev))
> + if (!mddev_set_bitmap_ops_nosysfs(mddev))
> return -ENOENT;
>
> err = mddev->bitmap_ops->create(mddev);
> @@ -6552,7 +6549,7 @@ static int md_bitmap_create(struct mddev
> *mddev)
> * doesn't match, and mdadm is not the latest version to set
> * bitmap_type, set bitmap_ops based on the disk version.
> */
> - mddev_clear_bitmap_ops(mddev);
> + mddev->bitmap_ops = NULL;
>
> sb_id = md_bitmap_get_id_from_sb(mddev);
> if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
> @@ -6562,27 +6559,50 @@ static int md_bitmap_create(struct mddev
> *mddev)
> mdname(mddev), orig_id, sb_id);
>
> mddev->bitmap_id = sb_id;
> - if (!mddev_set_bitmap_ops(mddev)) {
> + if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
> mddev->bitmap_id = orig_id;
> return -ENOENT;
> }
>
> err = mddev->bitmap_ops->create(mddev);
> if (err) {
> - mddev_clear_bitmap_ops(mddev);
> + mddev->bitmap_ops = NULL;
> mddev->bitmap_id = orig_id;
> }
>
> return err;
> }
>
> -static void md_bitmap_destroy(struct mddev *mddev)
> +static int md_bitmap_create(struct mddev *mddev)
> +{
> + int err;
> +
> + err = md_bitmap_create_nosysfs(mddev);
> + if (err)
> + return err;
> +
> + if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group)
> + md_bitmap_sysfs_add(mddev);
> +
> + return 0;
> +}
> +
> +static void md_bitmap_destroy_nosysfs(struct mddev *mddev)
> {
> if (!md_bitmap_registered(mddev))
> return;
>
> mddev->bitmap_ops->destroy(mddev);
> - mddev_clear_bitmap_ops(mddev);
> + mddev->bitmap_ops = NULL;
> +}
> +
> +static void md_bitmap_destroy(struct mddev *mddev)
> +{
> + if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
> + mddev->bitmap_ops->group)
> + md_bitmap_sysfs_del(mddev);
> +
> + md_bitmap_destroy_nosysfs(mddev);
> }
>
> int md_run(struct mddev *mddev)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v13 2/3] md/md-bitmap: split bitmap sysfs groups
2026-04-25 2:46 ` [PATCH v13 2/3] md/md-bitmap: split bitmap sysfs groups Yu Kuai
@ 2026-04-25 8:36 ` Su Yue
0 siblings, 0 replies; 9+ messages in thread
From: Su Yue @ 2026-04-25 8:36 UTC (permalink / raw)
To: Yu Kuai; +Cc: Song Liu, glass.su, Li Nan, Xiao Ni, linux-raid, linux-kernel
On Sat 25 Apr 2026 at 10:46, Yu Kuai <yukuai@fnnas.com> wrote:
> Split the classic bitmap sysfs files into a common bitmap group
> with
> the location attribute and a separate internal bitmap group for
> the
> remaining files.
>
> At the same time, convert bitmap operations from a single sysfs
> group
> to a sysfs group array so backends can share part of their sysfs
> layout while adding backend-specific attributes separately.
>
> Switch the bitmap sysfs helpers to use sysfs_update_groups() for
> the
> add and update path, and remove groups in reverse order so
> shared named
> groups are unmerged before the last group removes the directory.
>
> Also make bitmap operation lookup depend only on the currently
> selected
> bitmap id matching the installed backend. This prepares the
> lookup path
> for a later registered none backend.
>
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
> ---
> drivers/md/md-bitmap.c | 23 +++++++++++++++++++----
> drivers/md/md-bitmap.h | 2 +-
> drivers/md/md-llbitmap.c | 7 ++++++-
> drivers/md/md.c | 21 ++++++++++++++-------
> 4 files changed, 40 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
> index 83378c033c72..eba649703a1c 100644
> --- a/drivers/md/md-bitmap.c
> +++ b/drivers/md/md-bitmap.c
> @@ -2955,8 +2955,12 @@ 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[] = {
> +static struct attribute *md_bitmap_common_attrs[] = {
> &bitmap_location.attr,
> + NULL
> +};
> +
> +static struct attribute *md_bitmap_internal_attrs[] = {
> &bitmap_space.attr,
> &bitmap_timeout.attr,
> &bitmap_backlog.attr,
> @@ -2967,9 +2971,20 @@ static struct attribute
> *md_bitmap_attrs[] = {
> NULL
> };
>
> -static struct attribute_group md_bitmap_group = {
> +static struct attribute_group md_bitmap_common_group = {
> + .name = "bitmap",
> + .attrs = md_bitmap_common_attrs,
> +};
> +
> +static struct attribute_group md_bitmap_internal_group = {
> .name = "bitmap",
> - .attrs = md_bitmap_attrs,
> + .attrs = md_bitmap_internal_attrs,
> +};
> +
> +static const struct attribute_group *bitmap_groups[] = {
> + &md_bitmap_common_group,
> + &md_bitmap_internal_group,
> + NULL,
> };
>
> static struct bitmap_operations bitmap_ops = {
> @@ -3013,7 +3028,7 @@ static struct bitmap_operations bitmap_ops
> = {
> .set_pages = bitmap_set_pages,
> .free = md_bitmap_free,
>
> - .group = &md_bitmap_group,
> + .groups = bitmap_groups,
> };
>
> int md_bitmap_init(void)
> diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
> index b42a28fa83a0..214f623c7e79 100644
> --- a/drivers/md/md-bitmap.h
> +++ b/drivers/md/md-bitmap.h
> @@ -125,7 +125,7 @@ struct bitmap_operations {
> void (*set_pages)(void *data, unsigned long pages);
> void (*free)(void *data);
>
> - struct attribute_group *group;
> + const struct attribute_group **groups;
> };
>
> /* the bitmap API */
> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index 9e7e6b1a6f15..1adc5b117821 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -1738,6 +1738,11 @@ static struct attribute_group
> md_llbitmap_group = {
> .attrs = md_llbitmap_attrs,
> };
>
> +static const struct attribute_group *md_llbitmap_groups[] = {
> + &md_llbitmap_group,
> + NULL,
> +};
> +
> static struct bitmap_operations llbitmap_ops = {
> .head = {
> .type = MD_BITMAP,
> @@ -1774,7 +1779,7 @@ static struct bitmap_operations
> llbitmap_ops = {
> .dirty_bits = llbitmap_dirty_bits,
> .write_all = llbitmap_write_all,
>
> - .group = &md_llbitmap_group,
> + .groups = md_llbitmap_groups,
> };
>
> int md_llbitmap_init(void)
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 99aa1367c991..0ef81d116191 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -681,7 +681,7 @@ static void no_op(struct percpu_ref *r) {}
>
> static void md_bitmap_sysfs_add(struct mddev *mddev)
> {
> - if (sysfs_create_group(&mddev->kobj,
> mddev->bitmap_ops->group))
> + if (sysfs_update_groups(&mddev->kobj,
> mddev->bitmap_ops->groups))
> pr_warn("md: cannot register extra bitmap attributes for
> %s\n",
> mdname(mddev));
> else
> @@ -694,16 +694,23 @@ static void md_bitmap_sysfs_add(struct
> mddev *mddev)
>
> static void md_bitmap_sysfs_del(struct mddev *mddev)
> {
> - sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
> + int nr_groups = 0;
> +
> + for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups];
> nr_groups++)
> + ;
> +
> + while (--nr_groups >= 1)
> + sysfs_unmerge_group(&mddev->kobj,
> + mddev->bitmap_ops->groups[nr_groups]);
>
Amazing magic here!
Reviewed-by: Su Yue <glass.su@suse.com>
> + sysfs_remove_group(&mddev->kobj,
> mddev->bitmap_ops->groups[0]);
> }
>
> static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
> {
> - 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 (mddev->bitmap_ops &&
> + mddev->bitmap_ops->head.id == mddev->bitmap_id)
> return true;
>
> xa_lock(&md_submodule);
> @@ -6581,7 +6588,7 @@ static int md_bitmap_create(struct mddev
> *mddev)
> if (err)
> return err;
>
> - if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group)
> + if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
> md_bitmap_sysfs_add(mddev);
>
> return 0;
> @@ -6599,7 +6606,7 @@ static void
> md_bitmap_destroy_nosysfs(struct mddev *mddev)
> static void md_bitmap_destroy(struct mddev *mddev)
> {
> if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
> - mddev->bitmap_ops->group)
> + mddev->bitmap_ops->groups)
> md_bitmap_sysfs_del(mddev);
>
> md_bitmap_destroy_nosysfs(mddev);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v13 3/3] md/md-bitmap: add a none backend for bitmap grow
2026-04-25 2:46 ` [PATCH v13 3/3] md/md-bitmap: add a none backend for bitmap grow Yu Kuai
@ 2026-04-25 8:39 ` Su Yue
0 siblings, 0 replies; 9+ messages in thread
From: Su Yue @ 2026-04-25 8:39 UTC (permalink / raw)
To: Yu Kuai; +Cc: Song Liu, glass.su, Li Nan, Xiao Ni, linux-raid, linux-kernel
On Sat 25 Apr 2026 at 10:46, Yu Kuai <yukuai@fnnas.com> wrote:
> Add a real none bitmap backend that exposes the common bitmap
> sysfs
> group and use it to keep bitmap/location available when an array
> has no
> bitmap.
>
> Then switch the bitmap location sysfs path to move only between
> none
> and the classic bitmap backend, using the no-sysfs bitmap
> helpers while
> merging or unmerging the internal bitmap sysfs group.
>
> This restores mdadm --grow bitmap addition through
> bitmap/location.
>
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
>
Reviewed-by: Su Yue <glass.su@suse.com>
> ---
> drivers/md/md-bitmap.c | 108
> ++++++++++++++++++++++++++++++++++++++---
> drivers/md/md.c | 42 +++++++++++++---
> drivers/md/md.h | 3 ++
> 3 files changed, 137 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
> index eba649703a1c..028b9ca8ce52 100644
> --- a/drivers/md/md-bitmap.c
> +++ b/drivers/md/md-bitmap.c
> @@ -216,6 +216,7 @@ struct bitmap {
> };
>
> static struct workqueue_struct *md_bitmap_wq;
> +static struct attribute_group md_bitmap_internal_group;
>
> static int __bitmap_resize(struct bitmap *bitmap, sector_t
> blocks,
> int chunksize, bool init);
> @@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev
> *mddev, sector_t blocks, int chunksize)
> return __bitmap_resize(bitmap, blocks, chunksize, false);
> }
>
> +static bool bitmap_none_enabled(void *data, bool flush)
> +{
> + return false;
> +}
> +
> +static int bitmap_none_create(struct mddev *mddev)
> +{
> + return 0;
> +}
> +
> +static int bitmap_none_load(struct mddev *mddev)
> +{
> + return 0;
> +}
> +
> +static void bitmap_none_destroy(struct mddev *mddev)
> +{
> +}
> +
> +static int bitmap_none_get_stats(void *data, struct
> md_bitmap_stats *stats)
> +{
> + return -ENOENT;
> +}
> +
> static ssize_t
> location_show(struct mddev *mddev, char *page)
> {
> @@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const
> char *buf, size_t len)
> goto out;
> }
>
> - bitmap_destroy(mddev);
> + sysfs_unmerge_group(&mddev->kobj,
> &md_bitmap_internal_group);
> + md_bitmap_destroy_nosysfs(mddev);
> + mddev->bitmap_id = ID_BITMAP_NONE;
> + if (!mddev_set_bitmap_ops_nosysfs(mddev))
> + goto none_err;
> mddev->bitmap_info.offset = 0;
> if (mddev->bitmap_info.file) {
> struct file *f = mddev->bitmap_info.file;
> @@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev,
> const char *buf, size_t len)
> }
>
> mddev->bitmap_info.offset = offset;
> - rv = bitmap_create(mddev);
> + md_bitmap_destroy_nosysfs(mddev);
> + mddev->bitmap_id = ID_BITMAP;
> + if (!mddev_set_bitmap_ops_nosysfs(mddev))
> + goto bitmap_err;
> +
> + rv = md_bitmap_create_nosysfs(mddev);
> if (rv)
> - goto out;
> + goto create_err;
>
> - rv = bitmap_load(mddev);
> + rv = mddev->bitmap_ops->load(mddev);
> if (rv) {
> mddev->bitmap_info.offset = 0;
> - bitmap_destroy(mddev);
> - goto out;
> + goto load_err;
> }
> +
> + rv = sysfs_merge_group(&mddev->kobj,
> + &md_bitmap_internal_group);
> + if (rv)
> + goto merge_err;
> }
> }
> if (!mddev->external) {
> @@ -2679,6 +2717,22 @@ location_store(struct mddev *mddev, const
> char *buf, size_t len)
> if (rv)
> return rv;
> return len;
> +
> +merge_err:
> + mddev->bitmap_info.offset = 0;
> +load_err:
> + md_bitmap_destroy_nosysfs(mddev);
> +create_err:
> + mddev->bitmap_info.offset = 0;
> + mddev->bitmap_id = ID_BITMAP_NONE;
> + if (!mddev_set_bitmap_ops_nosysfs(mddev))
> + rv = -ENOENT;
> + goto out;
> +bitmap_err:
> + rv = -ENOENT;
> +none_err:
> + mddev->bitmap_info.offset = 0;
> + goto out;
> }
>
> static struct md_sysfs_entry bitmap_location =
> @@ -2987,6 +3041,27 @@ static const struct attribute_group
> *bitmap_groups[] = {
> NULL,
> };
>
> +static const struct attribute_group *bitmap_none_groups[] = {
> + &md_bitmap_common_group,
> + NULL,
> +};
> +
> +static struct bitmap_operations bitmap_none_ops = {
> + .head = {
> + .type = MD_BITMAP,
> + .id = ID_BITMAP_NONE,
> + .name = "none",
> + },
> +
> + .enabled = bitmap_none_enabled,
> + .create = bitmap_none_create,
> + .load = bitmap_none_load,
> + .destroy = bitmap_none_destroy,
> + .get_stats = bitmap_none_get_stats,
> +
> + .groups = bitmap_none_groups,
> +};
> +
> static struct bitmap_operations bitmap_ops = {
> .head = {
> .type = MD_BITMAP,
> @@ -3033,16 +3108,33 @@ static struct bitmap_operations
> bitmap_ops = {
>
> int md_bitmap_init(void)
> {
> + int err;
> +
> 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);
> + err = register_md_submodule(&bitmap_none_ops.head);
> + if (err)
> + goto err_wq;
> +
> + err = register_md_submodule(&bitmap_ops.head);
> + if (err)
> + goto err_none;
> +
> + return 0;
> +
> +err_none:
> + unregister_md_submodule(&bitmap_none_ops.head);
> +err_wq:
> + destroy_workqueue(md_bitmap_wq);
> + return err;
> }
>
> void md_bitmap_exit(void)
> {
> - destroy_workqueue(md_bitmap_wq);
> unregister_md_submodule(&bitmap_ops.head);
> + unregister_md_submodule(&bitmap_none_ops.head);
> + destroy_workqueue(md_bitmap_wq);
> }
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 0ef81d116191..7937b927d923 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -705,7 +705,7 @@ static void md_bitmap_sysfs_del(struct mddev
> *mddev)
> sysfs_remove_group(&mddev->kobj,
> mddev->bitmap_ops->groups[0]);
> }
>
> -static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
> +bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
> {
> struct md_submodule_head *head;
>
> @@ -4275,7 +4275,7 @@ bitmap_type_show(struct mddev *mddev, char
> *page)
>
> xa_lock(&md_submodule);
> xa_for_each(&md_submodule, i, head) {
> - if (head->type != MD_BITMAP)
> + if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE)
> continue;
>
> if (mddev->bitmap_id == head->id)
> @@ -6535,7 +6535,7 @@ static enum md_submodule_id
> md_bitmap_get_id_from_sb(struct mddev *mddev)
> return id;
> }
>
> -static int md_bitmap_create_nosysfs(struct mddev *mddev)
> +int md_bitmap_create_nosysfs(struct mddev *mddev)
> {
> enum md_submodule_id orig_id = mddev->bitmap_id;
> enum md_submodule_id sb_id;
> @@ -6544,8 +6544,10 @@ static int
> md_bitmap_create_nosysfs(struct mddev *mddev)
> if (mddev->bitmap_id == ID_BITMAP_NONE)
> return -EINVAL;
>
> - if (!mddev_set_bitmap_ops_nosysfs(mddev))
> + if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
> + mddev->bitmap_id = orig_id;
> return -ENOENT;
> + }
>
> err = mddev->bitmap_ops->create(mddev);
> if (!err)
> @@ -6559,8 +6561,10 @@ static int
> md_bitmap_create_nosysfs(struct mddev *mddev)
> mddev->bitmap_ops = NULL;
>
> sb_id = md_bitmap_get_id_from_sb(mddev);
> - if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
> + if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) {
> + mddev->bitmap_id = orig_id;
> return err;
> + }
>
> pr_info("md: %s: bitmap version mismatch, switching from %d to
> %d\n",
> mdname(mddev), orig_id, sb_id);
> @@ -6594,7 +6598,7 @@ static int md_bitmap_create(struct mddev
> *mddev)
> return 0;
> }
>
> -static void md_bitmap_destroy_nosysfs(struct mddev *mddev)
> +void md_bitmap_destroy_nosysfs(struct mddev *mddev)
> {
> if (!md_bitmap_registered(mddev))
> return;
> @@ -6612,6 +6616,16 @@ static void md_bitmap_destroy(struct
> mddev *mddev)
> md_bitmap_destroy_nosysfs(mddev);
> }
>
> +static void md_bitmap_set_none(struct mddev *mddev)
> +{
> + mddev->bitmap_id = ID_BITMAP_NONE;
> + if (!mddev_set_bitmap_ops_nosysfs(mddev))
> + return;
> +
> + if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
> + md_bitmap_sysfs_add(mddev);
> +}
> +
> int md_run(struct mddev *mddev)
> {
> int err;
> @@ -6821,6 +6835,10 @@ int md_run(struct mddev *mddev)
> if (mddev->sb_flags)
> md_update_sb(mddev, 0);
>
> + if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file
> &&
> + !mddev->bitmap_info.offset)
> + md_bitmap_set_none(mddev);
> +
> md_new_event();
> return 0;
>
> @@ -7766,7 +7784,8 @@ static int set_bitmap_file(struct mddev
> *mddev, int fd)
> {
> int err = 0;
>
> - if (!md_bitmap_registered(mddev))
> + if (!md_bitmap_registered(mddev) ||
> + mddev->bitmap_id == ID_BITMAP_NONE)
> return -EINVAL;
>
> if (mddev->pers) {
> @@ -7831,10 +7850,12 @@ static int set_bitmap_file(struct mddev
> *mddev, int fd)
>
> if (err) {
> md_bitmap_destroy(mddev);
> + md_bitmap_set_none(mddev);
> fd = -1;
> }
> } else if (fd < 0) {
> md_bitmap_destroy(mddev);
> + md_bitmap_set_none(mddev);
> }
> }
>
> @@ -8141,12 +8162,16 @@ static int update_array_info(struct
> mddev *mddev, mdu_array_info_t *info)
> mddev->bitmap_info.default_offset;
> mddev->bitmap_info.space =
> mddev->bitmap_info.default_space;
> + mddev->bitmap_id = ID_BITMAP;
> rv = md_bitmap_create(mddev);
> if (!rv)
> rv = mddev->bitmap_ops->load(mddev);
>
> - if (rv)
> + if (rv) {
> md_bitmap_destroy(mddev);
> + mddev->bitmap_info.offset = 0;
> + md_bitmap_set_none(mddev);
> + }
> } else {
> struct md_bitmap_stats stats;
>
> @@ -8174,6 +8199,7 @@ static int update_array_info(struct mddev
> *mddev, mdu_array_info_t *info)
> }
> md_bitmap_destroy(mddev);
> mddev->bitmap_info.offset = 0;
> + md_bitmap_set_none(mddev);
> }
> }
> md_update_sb(mddev, 1);
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index d3d4e2150dc8..52c378086046 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -934,6 +934,9 @@ extern void md_allow_write(struct mddev
> *mddev);
> extern void md_wait_for_blocked_rdev(struct md_rdev *rdev,
> struct mddev *mddev);
> extern void md_set_array_sectors(struct mddev *mddev, sector_t
> array_sectors);
> extern int md_check_no_bitmap(struct mddev *mddev);
> +bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev);
> +int md_bitmap_create_nosysfs(struct mddev *mddev);
> +void md_bitmap_destroy_nosysfs(struct mddev *mddev);
> extern int md_integrity_register(struct mddev *mddev);
> extern int strict_strtoul_scaled(const char *cp, unsigned long
> *res, int scale);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs
2026-04-25 2:46 [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
` (3 preceding siblings ...)
2026-04-25 2:49 ` [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
@ 2026-04-25 8:41 ` Su Yue
4 siblings, 0 replies; 9+ messages in thread
From: Su Yue @ 2026-04-25 8:41 UTC (permalink / raw)
To: Yu Kuai; +Cc: Song Liu, glass.su, Li Nan, Xiao Ni, linux-raid, linux-kernel
On Sat 25 Apr 2026 at 10:46, Yu Kuai <yukuai@fnnas.com> wrote:
> mdadm --grow adds an internal bitmap by writing bitmap/location
> for an
> array that currently has no bitmap. That requires the bitmap
> directory
> and location attribute to exist before the classic bitmap
> backend is
> created.
>
> This series separates bitmap backend lifetime from bitmap sysfs
> lifetime,
> splits the sysfs layout into common and backend-specific groups,
> and adds
> a small "none" bitmap backend. The none backend keeps
> bitmap/location
> available while no real bitmap is active, and the location store
> path can
> then switch between the none backend and the classic bitmap
> backend
> without tearing down the common bitmap sysfs directory.
>
> Patch 1 factors bitmap creation and destruction into helpers
> that do not
> touch sysfs registration.
>
> Patch 2 splits the classic bitmap sysfs files into a common
> group and an
> internal-bitmap group, and converts bitmap backend operations to
> use a
> sysfs group array.
>
> Patch 3 adds the none backend and uses it to restore mdadm
> --grow bitmap
> addition through bitmap/location.
>
> Changes since v12:
> - Keep the factoring patch focused on no-sysfs bitmap lifetime
> helpers.
> - Make bitmap operation lookup depend only on the current bitmap
> id
> matching the installed backend.
> - Trim the none backend to only the operations required by the
> active
> call paths.
> - Rework bitmap/location error handling with explicit cleanup
> labels.
> - Restore the none backend after bitmap removal and
> creation/load
> failures so bitmap/location stays available.
>
> Validation:
> - create a RAID1 array with --bitmap=none
> - verify /sys/block/md0/md/bitmap/location exists and reports
> "none"
> - mdadm --grow /dev/md0 --bitmap=internal
> - verify location switches to "+8", mdadm reports "Intent
> Bitmap:
> Internal", and /proc/mdstat reports a bitmap
> - mdadm --grow /dev/md0 --bitmap=none
> - verify location switches back to "none" and only the common
> location
> attribute remains under md/bitmap
> - repeat the internal/none switch once more
> - Checked the QEMU serial log for panic, Oops, BUG, WARNING,
> Call Trace,
> RCU stall, and hung-task patterns; none were found.
>
> Yu Kuai (3):
> md: factor bitmap creation away from sysfs handling
> md/md-bitmap: split bitmap sysfs groups
> md/md-bitmap: add a none backend for bitmap grow
>
Thanks for all.
Would you like to add tag Fixes: fb8cc3b0d9db for the whole series
while merging?
--
Su
> drivers/md/md-bitmap.c | 131
> +++++++++++++++++++++++++++++++++++----
> drivers/md/md-bitmap.h | 2 +-
> drivers/md/md-llbitmap.c | 7 ++-
> drivers/md/md.c | 125
> ++++++++++++++++++++++++++-----------
> drivers/md/md.h | 3 +
> 5 files changed, 218 insertions(+), 50 deletions(-)
>
> base-commit: c85d314b135ff569c1031f2ef8e40368bcfe72ac
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-04-25 8:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-25 2:46 [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
2026-04-25 2:46 ` [PATCH v13 1/3] md: factor bitmap creation away from sysfs handling Yu Kuai
2026-04-25 8:30 ` Su Yue
2026-04-25 2:46 ` [PATCH v13 2/3] md/md-bitmap: split bitmap sysfs groups Yu Kuai
2026-04-25 8:36 ` Su Yue
2026-04-25 2:46 ` [PATCH v13 3/3] md/md-bitmap: add a none backend for bitmap grow Yu Kuai
2026-04-25 8:39 ` Su Yue
2026-04-25 2:49 ` [PATCH v13 0/3] md/md-bitmap: restore bitmap grow through sysfs Yu Kuai
2026-04-25 8:41 ` Su Yue
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox