diff options
-rw-r--r-- | block/blk-sysfs.c | 34 | ||||
-rw-r--r-- | include/linux/blkdev.h | 2 |
2 files changed, 24 insertions, 12 deletions
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 283da7fbe034..27aceab1cc31 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c | |||
@@ -777,24 +777,25 @@ static void blk_free_queue_rcu(struct rcu_head *rcu_head) | |||
777 | } | 777 | } |
778 | 778 | ||
779 | /** | 779 | /** |
780 | * blk_release_queue: - release a &struct request_queue when it is no longer needed | 780 | * __blk_release_queue - release a request queue when it is no longer needed |
781 | * @kobj: the kobj belonging to the request queue to be released | 781 | * @work: pointer to the release_work member of the request queue to be released |
782 | * | 782 | * |
783 | * Description: | 783 | * Description: |
784 | * blk_release_queue is the pair to blk_init_queue() or | 784 | * blk_release_queue is the counterpart of blk_init_queue(). It should be |
785 | * blk_queue_make_request(). It should be called when a request queue is | 785 | * called when a request queue is being released; typically when a block |
786 | * being released; typically when a block device is being de-registered. | 786 | * device is being de-registered. Its primary task it to free the queue |
787 | * Currently, its primary task it to free all the &struct request | 787 | * itself. |
788 | * structures that were allocated to the queue and the queue itself. | ||
789 | * | 788 | * |
790 | * Note: | 789 | * Notes: |
791 | * The low level driver must have finished any outstanding requests first | 790 | * The low level driver must have finished any outstanding requests first |
792 | * via blk_cleanup_queue(). | 791 | * via blk_cleanup_queue(). |
793 | **/ | 792 | * |
794 | static void blk_release_queue(struct kobject *kobj) | 793 | * Although blk_release_queue() may be called with preemption disabled, |
794 | * __blk_release_queue() may sleep. | ||
795 | */ | ||
796 | static void __blk_release_queue(struct work_struct *work) | ||
795 | { | 797 | { |
796 | struct request_queue *q = | 798 | struct request_queue *q = container_of(work, typeof(*q), release_work); |
797 | container_of(kobj, struct request_queue, kobj); | ||
798 | 799 | ||
799 | if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags)) | 800 | if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags)) |
800 | blk_stat_remove_callback(q, q->poll_cb); | 801 | blk_stat_remove_callback(q, q->poll_cb); |
@@ -834,6 +835,15 @@ static void blk_release_queue(struct kobject *kobj) | |||
834 | call_rcu(&q->rcu_head, blk_free_queue_rcu); | 835 | call_rcu(&q->rcu_head, blk_free_queue_rcu); |
835 | } | 836 | } |
836 | 837 | ||
838 | static void blk_release_queue(struct kobject *kobj) | ||
839 | { | ||
840 | struct request_queue *q = | ||
841 | container_of(kobj, struct request_queue, kobj); | ||
842 | |||
843 | INIT_WORK(&q->release_work, __blk_release_queue); | ||
844 | schedule_work(&q->release_work); | ||
845 | } | ||
846 | |||
837 | static const struct sysfs_ops queue_sysfs_ops = { | 847 | static const struct sysfs_ops queue_sysfs_ops = { |
838 | .show = queue_attr_show, | 848 | .show = queue_attr_show, |
839 | .store = queue_attr_store, | 849 | .store = queue_attr_store, |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ab92c4ea138b..b74a3edcb3da 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -586,6 +586,8 @@ struct request_queue { | |||
586 | 586 | ||
587 | size_t cmd_size; | 587 | size_t cmd_size; |
588 | void *rq_alloc_data; | 588 | void *rq_alloc_data; |
589 | |||
590 | struct work_struct release_work; | ||
589 | }; | 591 | }; |
590 | 592 | ||
591 | #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ | 593 | #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ |