md/md-bitmap: delay registration of bitmap_ops until creating bitmap

Currently bitmap_ops is registered while allocating mddev, this is fine
when there is only one bitmap_ops.

Delay setting bitmap_ops until creating bitmap, so that user can choose
which bitmap to use before running the array.

Link: https://lore.kernel.org/linux-raid/20250721171557.34587-7-yukuai@kernel.org
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Li Nan <linan122@huawei.com>
Reviewed-by: Xiao Ni <xni@redhat.com>
This commit is contained in:
Yu Kuai
2025-08-29 16:04:21 +08:00
parent 180b82c1c7
commit fb8cc3b0d9
2 changed files with 56 additions and 37 deletions

View File

@@ -678,9 +678,11 @@ static void no_op(struct percpu_ref *r) {}
static bool mddev_set_bitmap_ops(struct mddev *mddev)
{
struct bitmap_operations *old = mddev->bitmap_ops;
struct md_submodule_head *head;
if (mddev->bitmap_id == ID_BITMAP_NONE)
if (mddev->bitmap_id == ID_BITMAP_NONE ||
(old && old->head.id == mddev->bitmap_id))
return true;
xa_lock(&md_submodule);
@@ -698,6 +700,18 @@ 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:
@@ -707,28 +721,26 @@ err:
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)
{
if (!IS_ENABLED(CONFIG_MD_BITMAP)) {
if (!IS_ENABLED(CONFIG_MD_BITMAP))
mddev->bitmap_id = ID_BITMAP_NONE;
} else {
else
mddev->bitmap_id = ID_BITMAP;
if (!mddev_set_bitmap_ops(mddev))
return -EINVAL;
}
if (percpu_ref_init(&mddev->active_io, active_io_release,
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
mddev_clear_bitmap_ops(mddev);
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL))
return -ENOMEM;
}
if (percpu_ref_init(&mddev->writes_pending, no_op,
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
mddev_clear_bitmap_ops(mddev);
percpu_ref_exit(&mddev->active_io);
return -ENOMEM;
}
@@ -766,7 +778,6 @@ EXPORT_SYMBOL_GPL(mddev_init);
void mddev_destroy(struct mddev *mddev)
{
mddev_clear_bitmap_ops(mddev);
percpu_ref_exit(&mddev->active_io);
percpu_ref_exit(&mddev->writes_pending);
}
@@ -6196,11 +6207,6 @@ struct mddev *md_alloc(dev_t dev, char *name)
return ERR_PTR(error);
}
if (md_bitmap_registered(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));
kobject_uevent(&mddev->kobj, KOBJ_ADD);
mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd, "level");
@@ -6279,6 +6285,26 @@ static void md_safemode_timeout(struct timer_list *t)
static int start_dirty_degraded;
static int md_bitmap_create(struct mddev *mddev)
{
if (mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
if (!mddev_set_bitmap_ops(mddev))
return -ENOENT;
return mddev->bitmap_ops->create(mddev);
}
static void md_bitmap_destroy(struct mddev *mddev)
{
if (!md_bitmap_registered(mddev))
return;
mddev->bitmap_ops->destroy(mddev);
mddev_clear_bitmap_ops(mddev);
}
int md_run(struct mddev *mddev)
{
int err;
@@ -6443,9 +6469,9 @@ int md_run(struct mddev *mddev)
(unsigned long long)pers->size(mddev, 0, 0) / 2);
err = -EINVAL;
}
if (err == 0 && pers->sync_request && md_bitmap_registered(mddev) &&
if (err == 0 && pers->sync_request &&
(mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
err = mddev->bitmap_ops->create(mddev);
err = md_bitmap_create(mddev);
if (err)
pr_warn("%s: failed to create bitmap (%d)\n",
mdname(mddev), err);
@@ -6518,8 +6544,7 @@ bitmap_abort:
pers->free(mddev, mddev->private);
mddev->private = NULL;
put_pers(pers);
if (md_bitmap_registered(mddev))
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
abort:
bioset_exit(&mddev->io_clone_set);
exit_sync_set:
@@ -6542,7 +6567,7 @@ int do_md_run(struct mddev *mddev)
if (md_bitmap_registered(mddev)) {
err = mddev->bitmap_ops->load(mddev);
if (err) {
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
goto out;
}
}
@@ -6740,8 +6765,7 @@ static void __md_stop(struct mddev *mddev)
{
struct md_personality *pers = mddev->pers;
if (md_bitmap_registered(mddev))
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
mddev_detach(mddev);
spin_lock(&mddev->lock);
mddev->pers = NULL;
@@ -7518,16 +7542,16 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
err = 0;
if (mddev->pers) {
if (fd >= 0) {
err = mddev->bitmap_ops->create(mddev);
err = md_bitmap_create(mddev);
if (!err)
err = mddev->bitmap_ops->load(mddev);
if (err) {
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
fd = -1;
}
} else if (fd < 0) {
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
}
}
@@ -7812,14 +7836,6 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
rv = update_raid_disks(mddev, info->raid_disks);
if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) {
/*
* Metadata says bitmap existed, however kernel can't find
* registered bitmap.
*/
if (WARN_ON_ONCE(!md_bitmap_registered(mddev))) {
rv = -EINVAL;
goto err;
}
if (mddev->pers->quiesce == NULL || mddev->thread == NULL) {
rv = -EINVAL;
goto err;
@@ -7842,12 +7858,12 @@ 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;
rv = mddev->bitmap_ops->create(mddev);
rv = md_bitmap_create(mddev);
if (!rv)
rv = mddev->bitmap_ops->load(mddev);
if (rv)
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
} else {
struct md_bitmap_stats stats;
@@ -7873,7 +7889,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
put_cluster_ops(mddev);
mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
}
mddev->bitmap_ops->destroy(mddev);
md_bitmap_destroy(mddev);
mddev->bitmap_info.offset = 0;
}
}