aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/raid10.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-09-21 15:30:20 +1000
committerGreg Kroah-Hartman <gregkh@suse.de>2011-10-16 14:14:53 -0700
commit7f3b5ef8184a929f56293d6c7a88f426c7b74558 (patch)
tree817b10c76033ad291f9e5d5d56259855016ed190 /drivers/md/raid10.c
parent57fb87f0a640cd7b2e7cde21fd7c13138f8ef75b (diff)
downloadkernel_samsung_tuna-7f3b5ef8184a929f56293d6c7a88f426c7b74558.tar.gz
kernel_samsung_tuna-7f3b5ef8184a929f56293d6c7a88f426c7b74558.tar.bz2
kernel_samsung_tuna-7f3b5ef8184a929f56293d6c7a88f426c7b74558.zip
md: Avoid waking up a thread after it has been freed.
commit 01f96c0a9922cd9919baf9d16febdf7016177a12 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/md/raid10.c')
-rw-r--r--drivers/md/raid10.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 6e846688962..17cb6ab6230 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2331,7 +2331,7 @@ static int run(mddev_t *mddev)
return 0;
out_free_conf:
- md_unregister_thread(mddev->thread);
+ md_unregister_thread(&mddev->thread);
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
safe_put_page(conf->tmppage);
@@ -2349,8 +2349,7 @@ static int stop(mddev_t *mddev)
raise_barrier(conf, 0);
lower_barrier(conf);
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);