Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 963c555e authored by Guoqing Jiang's avatar Guoqing Jiang Committed by Song Liu
Browse files

md: introduce mddev_create/destroy_wb_pool for the change of member device



Previously, we called rdev_init_wb to avoid potential data
inconsistency when array is created.

Now, we need to call the function and create mempool if a
device is added or just be flaged as "writemostly". So
mddev_create_wb_pool is introduced and called accordingly.
And for safety reason, we mark implicit GFP_NOIO allocation
scope for create mempool during mddev_suspend/mddev_resume.

And mempool should be removed conversely after remove a
member device or its's "writemostly" flag, which is done
by call mddev_destroy_wb_pool.

Reviewed-by: default avatarNeilBrown <neilb@suse.com>
Signed-off-by: default avatarGuoqing Jiang <gqjiang@suse.com>
Signed-off-by: default avatarSong Liu <songliubraving@fb.com>
parent 3e148a32
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@

*/

#include <linux/sched/mm.h>
#include <linux/sched/signal.h>
#include <linux/kthread.h>
#include <linux/blkdev.h>
@@ -137,6 +138,64 @@ static int rdev_init_wb(struct md_rdev *rdev)
	return 1;
}

/*
 * Create wb_info_pool if rdev is the first multi-queue device flaged
 * with writemostly, also write-behind mode is enabled.
 */
void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev,
			  bool is_suspend)
{
	if (mddev->bitmap_info.max_write_behind == 0)
		return;

	if (!test_bit(WriteMostly, &rdev->flags) || !rdev_init_wb(rdev))
		return;

	if (mddev->wb_info_pool == NULL) {
		unsigned int noio_flag;

		if (!is_suspend)
			mddev_suspend(mddev);
		noio_flag = memalloc_noio_save();
		mddev->wb_info_pool = mempool_create_kmalloc_pool(NR_WB_INFOS,
							sizeof(struct wb_info));
		memalloc_noio_restore(noio_flag);
		if (!mddev->wb_info_pool)
			pr_err("can't alloc memory pool for writemostly\n");
		if (!is_suspend)
			mddev_resume(mddev);
	}
}
EXPORT_SYMBOL_GPL(mddev_create_wb_pool);

/*
 * destroy wb_info_pool if rdev is the last device flaged with WBCollisionCheck.
 */
static void mddev_destroy_wb_pool(struct mddev *mddev, struct md_rdev *rdev)
{
	if (!test_and_clear_bit(WBCollisionCheck, &rdev->flags))
		return;

	if (mddev->wb_info_pool) {
		struct md_rdev *temp;
		int num = 0;

		/*
		 * Check if other rdevs need wb_info_pool.
		 */
		rdev_for_each(temp, mddev)
			if (temp != rdev &&
			    test_bit(WBCollisionCheck, &temp->flags))
				num++;
		if (!num) {
			mddev_suspend(rdev->mddev);
			mempool_destroy(mddev->wb_info_pool);
			mddev->wb_info_pool = NULL;
			mddev_resume(rdev->mddev);
		}
	}
}

static struct ctl_table_header *raid_table_header;

static struct ctl_table raid_table[] = {
@@ -2223,6 +2282,9 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
	rdev->mddev = mddev;
	pr_debug("md: bind<%s>\n", b);

	if (mddev->raid_disks)
		mddev_create_wb_pool(mddev, rdev, false);

	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
		goto fail;

@@ -2259,6 +2321,7 @@ static void unbind_rdev_from_array(struct md_rdev *rdev)
	bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
	list_del_rcu(&rdev->same_set);
	pr_debug("md: unbind<%s>\n", bdevname(rdev->bdev,b));
	mddev_destroy_wb_pool(rdev->mddev, rdev);
	rdev->mddev = NULL;
	sysfs_remove_link(&rdev->kobj, "block");
	sysfs_put(rdev->sysfs_state);
@@ -2771,8 +2834,10 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
		}
	} else if (cmd_match(buf, "writemostly")) {
		set_bit(WriteMostly, &rdev->flags);
		mddev_create_wb_pool(rdev->mddev, rdev, false);
		err = 0;
	} else if (cmd_match(buf, "-writemostly")) {
		mddev_destroy_wb_pool(rdev->mddev, rdev);
		clear_bit(WriteMostly, &rdev->flags);
		err = 0;
	} else if (cmd_match(buf, "blocked")) {
+2 −0
Original line number Diff line number Diff line
@@ -730,6 +730,8 @@ extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
extern void md_reload_sb(struct mddev *mddev, int raid_disk);
extern void md_update_sb(struct mddev *mddev, int force);
extern void md_kick_rdev_from_array(struct md_rdev * rdev);
extern void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev,
				 bool is_suspend);
struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);