summaryrefslogtreecommitdiffstats
path: root/drivers/md/multipath.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-09-21 07:30:20 +0200
committerNeilBrown <neilb@suse.de>2011-09-21 07:30:20 +0200
commit01f96c0a9922cd9919baf9d16febdf7016177a12 (patch)
treea877fe509c4ef0db5252b7192df56009c1d06d6f /drivers/md/multipath.c
parentmd: Fix handling for devices from 2TB to 4TB in 0.90 metadata. (diff)
downloadlinux-01f96c0a9922cd9919baf9d16febdf7016177a12.tar.xz
linux-01f96c0a9922cd9919baf9d16febdf7016177a12.zip
md: Avoid waking up a thread after it has been freed.
Two related problems: 1/ some error paths call "md_unregister_thread(mddev->thread)" without subsequently clearing ->thread. A subsequent call to mddev_unlock will try to wake the thread, and crash. 2/ Most calls to md_wakeup_thread are protected against the thread disappeared either by: - holding the ->mutex - having an active request, so something else must be keeping the array active. However mddev_unlock calls md_wakeup_thread after dropping the mutex and without any certainty of an active request, so the ->thread could theoretically disappear. So we need a spinlock to provide some protections. So change md_unregister_thread to take a pointer to the thread pointer, and ensure that it always does the required locking, and clears the pointer properly. Reported-by: "Moshe Melnikov" <moshe@zadarastorage.com> Signed-off-by: NeilBrown <neilb@suse.de> cc: stable@kernel.org
Diffstat (limited to 'drivers/md/multipath.c')
-rw-r--r--drivers/md/multipath.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 3535c23af288..d5b5fb300171 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -514,8 +514,7 @@ static int multipath_stop (mddev_t *mddev)
{
multipath_conf_t *conf = mddev->private;
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
mempool_destroy(conf->pool);
kfree(conf->multipaths);