Commit e98a235f authored by Yu Kuai's avatar Yu Kuai Committed by Jialin Zhang
Browse files

md: refactor action_store() for 'idle' and 'frozen'

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6OMCC


CVE: NA

--------------------------------

Prepare to handle 'idle' and 'frozen' differently to fix a deadlock, there
are no functional changes except that MD_RECOVERY_RUNNING is checked
again after 'reconfig_mutex' is held.

Signed-off-by: default avatarYu Kuai <yukuai3@huawei.com>
Reviewed-by: default avatarHou Tao <houtao1@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parent 4a53e631
Loading
Loading
Loading
Loading
+45 −16
Original line number Diff line number Diff line
@@ -4855,29 +4855,58 @@ action_show(struct mddev *mddev, char *page)
	return sprintf(page, "%s\n", type);
}

static ssize_t
action_store(struct mddev *mddev, const char *page, size_t len)
static void stop_sync_thread(struct mddev *mddev)
{
	if (!mddev->pers || !mddev->pers->sync_request)
		return -EINVAL;
	if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
		return;

	if (mddev_lock(mddev))
		return;

	/*
	 * Check again in case MD_RECOVERY_RUNNING is cleared before lock is
	 * held.
	 */
	if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
		mddev_unlock(mddev);
		return;
	}

	if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
		if (cmd_match(page, "frozen"))
			set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
		else
			clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
		if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
		    mddev_lock(mddev) == 0) {
	if (work_pending(&mddev->del_work))
		flush_workqueue(md_misc_wq);

	if (mddev->sync_thread) {
		set_bit(MD_RECOVERY_INTR, &mddev->recovery);
		md_reap_sync_thread(mddev);
	}

	mddev_unlock(mddev);
}
	} else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))

static void idle_sync_thread(struct mddev *mddev)
{
	clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
	stop_sync_thread(mddev);
}

static void frozen_sync_thread(struct mddev *mddev)
{
	set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
	stop_sync_thread(mddev);
}

static ssize_t
action_store(struct mddev *mddev, const char *page, size_t len)
{
	if (!mddev->pers || !mddev->pers->sync_request)
		return -EINVAL;


	if (cmd_match(page, "idle"))
		idle_sync_thread(mddev);
	else if (cmd_match(page, "frozen"))
		frozen_sync_thread(mddev);
	else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
		return -EBUSY;
	else if (cmd_match(page, "resync"))
		clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);