From 854d7a6fa60eaa67ef26fb0559b01a2cfb2fbcae Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Wed, 10 Nov 2004 21:48:51 -0800 Subject: [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: Neil Brown Contributions from Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 26 ++++++++++++++++++++++---- drivers/md/linear.c | 1 + drivers/md/multipath.c | 1 + drivers/md/raid0.c | 1 + drivers/md/raid1.c | 1 + drivers/md/raid10.c | 1 + drivers/md/raid5.c | 1 + drivers/md/raid6main.c | 1 + include/linux/blkdev.h | 1 + 9 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 12958fa9ea82..7aac17054084 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -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); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 6fb445a5c4f4..09e32023083c 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -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); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index cbce9d22093e..309398219556 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -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); diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 76c59f160447..e7d934eca06f 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -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); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6fc90e363644..4e25ebd53385 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -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) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 9596358572e3..271566095306 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -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) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 90dd9f8a596a..1dceb098a7fb 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -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; diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index ac588c53c3cb..9a27f8f88a91 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -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; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f04b0e223d82..1b7dc44bf3c1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -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 *); -- cgit v1.2.3