summaryrefslogtreecommitdiffstats
path: root/block/blk-sysfs.c
diff options
context:
space:
mode:
authorBart Van Assche <bart.vanassche@sandisk.com>2017-06-14 15:27:50 -0400
committerJens Axboe <axboe@fb.com>2017-06-14 15:27:50 -0400
commitdc9edc44de6cd7cc8cc7f5b36c1adb221eda3207 (patch)
treef749db9a9accb61b5b6e7d0d88b4e45b16326a46 /block/blk-sysfs.c
parent63f700aab4c11d46626de3cd051dae56cf7e9056 (diff)
block: Fix a blk_exit_rl() regression
Avoid that the following complaint is reported: BUG: sleeping function called from invalid context at kernel/workqueue.c:2790 in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3 1 lock held by rcuop/3/41: #0: (rcu_callback){......}, at: [<ffffffff8111f9a2>] rcu_nocb_kthread+0x282/0x500 Call Trace: dump_stack+0x86/0xcf ___might_sleep+0x174/0x260 __might_sleep+0x4a/0x80 flush_work+0x7e/0x2e0 __cancel_work_timer+0x143/0x1c0 cancel_work_sync+0x10/0x20 blk_throtl_exit+0x25/0x60 blkcg_exit_queue+0x35/0x40 blk_release_queue+0x42/0x130 kobject_put+0xa9/0x190 This happens since we invoke callbacks that need to block from the queue release handler. Fix this by pushing the final release to a workqueue. Reported-by: Ross Zwisler <zwisler@gmail.com> Fixes: commit b425e5049258 ("block: Avoid that blk_exit_rl() triggers a use-after-free") Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Tested-by: Ross Zwisler <ross.zwisler@linux.intel.com> Updated changelog Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block/blk-sysfs.c')
-rw-r--r--block/blk-sysfs.c34
1 files changed, 22 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 *
794static 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 */
796static 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
838static 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
837static const struct sysfs_ops queue_sysfs_ops = { 847static 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,