Commit fb8cc3b0 authored by Yu Kuai's avatar Yu Kuai
Browse files

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: default avatarYu Kuai <yukuai3@huawei.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarLi Nan <linan122@huawei.com>
Reviewed-by: default avatarXiao Ni <xni@redhat.com>
parent 180b82c1
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -388,6 +388,9 @@ All md devices contain:
     bitmap
         The default internal bitmap

If bitmap_type is not none, then additional bitmap attributes bitmap/xxx or
llbitmap/xxx will be created after md device KOBJ_CHANGE event.

If bitmap_type is bitmap, then the md device will also contain:

  bitmap/location
+53 −37
Original line number Diff line number Diff line
@@ -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 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)

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 @@ int md_run(struct mddev *mddev)
		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;
		}
	}