Commit 854d7a6f authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] md: delete unplug timer before shutting down md array

As the unplug timer can potentially fire at any time, and and it access
data that is released by the md ->stop function, we need to del_timer_sync
before releasing that data.

(After much discussion, we created blk_sync_queue() for this)
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Contributions from Jens Axboe <axboe@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c07e1a69
...@@ -1357,9 +1357,29 @@ void blk_stop_queue(request_queue_t *q) ...@@ -1357,9 +1357,29 @@ void blk_stop_queue(request_queue_t *q)
blk_remove_plug(q); blk_remove_plug(q);
set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
} }
EXPORT_SYMBOL(blk_stop_queue); EXPORT_SYMBOL(blk_stop_queue);
/**
* blk_sync_queue - cancel any pending callbacks on a queue
* @q: the queue
*
* Description:
* The block layer may perform asynchronous callback activity
* on a queue, such as calling the unplug function after a timeout.
* A block device may call blk_sync_queue to ensure that any
* such activity is cancelled, thus allowing it to release resources
* the the callbacks might use. The caller must already have made sure
* that its ->make_request_fn will not re-add plugging prior to calling
* this function.
*
*/
void blk_sync_queue(struct request_queue *q)
{
del_timer_sync(&q->unplug_timer);
kblockd_flush();
}
EXPORT_SYMBOL(blk_sync_queue);
/** /**
* blk_run_queue - run a single device queue * blk_run_queue - run a single device queue
* @q: The queue to run * @q: The queue to run
...@@ -1373,7 +1393,6 @@ void blk_run_queue(struct request_queue *q) ...@@ -1373,7 +1393,6 @@ void blk_run_queue(struct request_queue *q)
q->request_fn(q); q->request_fn(q);
spin_unlock_irqrestore(q->queue_lock, flags); spin_unlock_irqrestore(q->queue_lock, flags);
} }
EXPORT_SYMBOL(blk_run_queue); EXPORT_SYMBOL(blk_run_queue);
/** /**
...@@ -1401,8 +1420,7 @@ void blk_cleanup_queue(request_queue_t * q) ...@@ -1401,8 +1420,7 @@ void blk_cleanup_queue(request_queue_t * q)
if (q->elevator) if (q->elevator)
elevator_exit(q->elevator); elevator_exit(q->elevator);
del_timer_sync(&q->unplug_timer); blk_sync_queue(q);
kblockd_flush();
if (rl->rq_pool) if (rl->rq_pool)
mempool_destroy(rl->rq_pool); mempool_destroy(rl->rq_pool);
......
...@@ -231,6 +231,7 @@ static int linear_stop (mddev_t *mddev) ...@@ -231,6 +231,7 @@ static int linear_stop (mddev_t *mddev)
{ {
linear_conf_t *conf = mddev_to_conf(mddev); linear_conf_t *conf = mddev_to_conf(mddev);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf->hash_table); kfree(conf->hash_table);
kfree(conf); kfree(conf);
......
...@@ -547,6 +547,7 @@ static int multipath_stop (mddev_t *mddev) ...@@ -547,6 +547,7 @@ static int multipath_stop (mddev_t *mddev)
md_unregister_thread(mddev->thread); md_unregister_thread(mddev->thread);
mddev->thread = NULL; mddev->thread = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
mempool_destroy(conf->pool); mempool_destroy(conf->pool);
kfree(conf->multipaths); kfree(conf->multipaths);
kfree(conf); kfree(conf);
......
...@@ -385,6 +385,7 @@ static int raid0_stop (mddev_t *mddev) ...@@ -385,6 +385,7 @@ static int raid0_stop (mddev_t *mddev)
{ {
raid0_conf_t *conf = mddev_to_conf(mddev); raid0_conf_t *conf = mddev_to_conf(mddev);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree (conf->hash_table); kfree (conf->hash_table);
conf->hash_table = NULL; conf->hash_table = NULL;
kfree (conf->strip_zone); kfree (conf->strip_zone);
......
...@@ -1293,6 +1293,7 @@ static int stop(mddev_t *mddev) ...@@ -1293,6 +1293,7 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread); md_unregister_thread(mddev->thread);
mddev->thread = NULL; mddev->thread = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r1bio_pool) if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool); mempool_destroy(conf->r1bio_pool);
if (conf->mirrors) if (conf->mirrors)
......
...@@ -1744,6 +1744,7 @@ static int stop(mddev_t *mddev) ...@@ -1744,6 +1744,7 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread); md_unregister_thread(mddev->thread);
mddev->thread = NULL; mddev->thread = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r10bio_pool) if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool); mempool_destroy(conf->r10bio_pool);
if (conf->mirrors) if (conf->mirrors)
......
...@@ -1707,6 +1707,7 @@ static int stop (mddev_t *mddev) ...@@ -1707,6 +1707,7 @@ static int stop (mddev_t *mddev)
mddev->thread = NULL; mddev->thread = NULL;
shrink_stripes(conf); shrink_stripes(conf);
free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf); kfree(conf);
mddev->private = NULL; mddev->private = NULL;
return 0; return 0;
......
...@@ -1878,6 +1878,7 @@ static int stop (mddev_t *mddev) ...@@ -1878,6 +1878,7 @@ static int stop (mddev_t *mddev)
mddev->thread = NULL; mddev->thread = NULL;
shrink_stripes(conf); shrink_stripes(conf);
free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf); kfree(conf);
mddev->private = NULL; mddev->private = NULL;
return 0; return 0;
......
...@@ -522,6 +522,7 @@ extern int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *) ...@@ -522,6 +522,7 @@ extern int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *)
extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
extern void blk_start_queue(request_queue_t *q); extern void blk_start_queue(request_queue_t *q);
extern void blk_stop_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q);
extern void blk_sync_queue(struct request_queue *q);
extern void __blk_stop_queue(request_queue_t *q); extern void __blk_stop_queue(request_queue_t *q);
extern void blk_run_queue(request_queue_t *); extern void blk_run_queue(request_queue_t *);
extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment