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)
blk_remove_plug(q);
set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
}
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
* @q: The queue to run
......@@ -1373,7 +1393,6 @@ void blk_run_queue(struct request_queue *q)
q->request_fn(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
EXPORT_SYMBOL(blk_run_queue);
/**
......@@ -1401,8 +1420,7 @@ void blk_cleanup_queue(request_queue_t * q)
if (q->elevator)
elevator_exit(q->elevator);
del_timer_sync(&q->unplug_timer);
kblockd_flush();
blk_sync_queue(q);
if (rl->rq_pool)
mempool_destroy(rl->rq_pool);
......
......@@ -231,6 +231,7 @@ static int linear_stop (mddev_t *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);
......
......@@ -547,6 +547,7 @@ static int multipath_stop (mddev_t *mddev)
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
mempool_destroy(conf->pool);
kfree(conf->multipaths);
kfree(conf);
......
......@@ -385,6 +385,7 @@ static int raid0_stop (mddev_t *mddev)
{
raid0_conf_t *conf = mddev_to_conf(mddev);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree (conf->hash_table);
conf->hash_table = NULL;
kfree (conf->strip_zone);
......
......@@ -1293,6 +1293,7 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
if (conf->mirrors)
......
......@@ -1744,6 +1744,7 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
if (conf->mirrors)
......
......@@ -1707,6 +1707,7 @@ static int stop (mddev_t *mddev)
mddev->thread = NULL;
shrink_stripes(conf);
free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf);
mddev->private = NULL;
return 0;
......
......@@ -1878,6 +1878,7 @@ static int stop (mddev_t *mddev)
mddev->thread = NULL;
shrink_stripes(conf);
free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf);
mddev->private = NULL;
return 0;
......
......@@ -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 void blk_start_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_run_queue(request_queue_t *);
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