diff options
| author | NeilBrown <neilb@suse.de> | 2011-09-21 15:30:20 +1000 | 
|---|---|---|
| committer | NeilBrown <neilb@suse.de> | 2011-09-21 15:30:20 +1000 | 
| commit | 01f96c0a9922cd9919baf9d16febdf7016177a12 (patch) | |
| tree | a877fe509c4ef0db5252b7192df56009c1d06d6f /drivers/md/multipath.c | |
| parent | 27a7b260f71439c40546b43588448faac01adb93 (diff) | |
| download | olio-linux-3.10-01f96c0a9922cd9919baf9d16febdf7016177a12.tar.xz olio-linux-3.10-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.c | 3 | 
1 files changed, 1 insertions, 2 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 3535c23af28..d5b5fb30017 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);  |