diff options
author | NeilBrown <neilb@suse.de> | 2015-05-28 03:53:29 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2015-05-28 04:04:45 -0400 |
commit | 56ccc1125bc141cf63927eda7febff4216dea2d3 (patch) | |
tree | 3af5cac150be4c0cf4d2e0d46dc9fba1328b8670 /drivers/md | |
parent | 626f2092c85ac847bb80b3257eb6a565dec32278 (diff) |
md: fix race when unfreezing sync_action
A recent change removed the need for locking around writing
to "sync_action" (and various other places), but introduced a
subtle race.
When e.g. setting 'reshape' on a 'frozen' array, the 'frozen'
flag is cleared before 'reshape' is set, so the md thread can
get in and start trying recovery - which isn't wanted.
So instead of clearing MD_RECOVERY_FROZEN for any command
except 'frozen', only clear it when each specific command
is parsed. This allows the handling of 'reshape' to clear
the bit while a lock is held.
Also remove some places where we set MD_RECOVERY_NEEDED,
as it is always set on non-error exit of the function.
Signed-off-by: NeilBrown <neilb@suse.de>
Fixes: 6791875e2e53 ("md: make reconfig_mutex optional for writes to md sysfs files.")
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/md.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index d4f31e195e26..8f10f4ea70ea 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -4211,12 +4211,12 @@ action_store(struct mddev *mddev, const char *page, size_t len) | |||
4211 | if (!mddev->pers || !mddev->pers->sync_request) | 4211 | if (!mddev->pers || !mddev->pers->sync_request) |
4212 | return -EINVAL; | 4212 | return -EINVAL; |
4213 | 4213 | ||
4214 | if (cmd_match(page, "frozen")) | ||
4215 | set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4216 | else | ||
4217 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4218 | 4214 | ||
4219 | if (cmd_match(page, "idle") || cmd_match(page, "frozen")) { | 4215 | if (cmd_match(page, "idle") || cmd_match(page, "frozen")) { |
4216 | if (cmd_match(page, "frozen")) | ||
4217 | set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4218 | else | ||
4219 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4220 | flush_workqueue(md_misc_wq); | 4220 | flush_workqueue(md_misc_wq); |
4221 | if (mddev->sync_thread) { | 4221 | if (mddev->sync_thread) { |
4222 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 4222 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
@@ -4229,16 +4229,17 @@ action_store(struct mddev *mddev, const char *page, size_t len) | |||
4229 | test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) | 4229 | test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) |
4230 | return -EBUSY; | 4230 | return -EBUSY; |
4231 | else if (cmd_match(page, "resync")) | 4231 | else if (cmd_match(page, "resync")) |
4232 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 4232 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); |
4233 | else if (cmd_match(page, "recover")) { | 4233 | else if (cmd_match(page, "recover")) { |
4234 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4234 | set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); | 4235 | set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); |
4235 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | ||
4236 | } else if (cmd_match(page, "reshape")) { | 4236 | } else if (cmd_match(page, "reshape")) { |
4237 | int err; | 4237 | int err; |
4238 | if (mddev->pers->start_reshape == NULL) | 4238 | if (mddev->pers->start_reshape == NULL) |
4239 | return -EINVAL; | 4239 | return -EINVAL; |
4240 | err = mddev_lock(mddev); | 4240 | err = mddev_lock(mddev); |
4241 | if (!err) { | 4241 | if (!err) { |
4242 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4242 | err = mddev->pers->start_reshape(mddev); | 4243 | err = mddev->pers->start_reshape(mddev); |
4243 | mddev_unlock(mddev); | 4244 | mddev_unlock(mddev); |
4244 | } | 4245 | } |
@@ -4250,6 +4251,7 @@ action_store(struct mddev *mddev, const char *page, size_t len) | |||
4250 | set_bit(MD_RECOVERY_CHECK, &mddev->recovery); | 4251 | set_bit(MD_RECOVERY_CHECK, &mddev->recovery); |
4251 | else if (!cmd_match(page, "repair")) | 4252 | else if (!cmd_match(page, "repair")) |
4252 | return -EINVAL; | 4253 | return -EINVAL; |
4254 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
4253 | set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); | 4255 | set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); |
4254 | set_bit(MD_RECOVERY_SYNC, &mddev->recovery); | 4256 | set_bit(MD_RECOVERY_SYNC, &mddev->recovery); |
4255 | } | 4257 | } |