Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Bart Van Assche and committed by
Jens Axboe
dc9edc44 63f700aa

+24 -12
+22 -12
block/blk-sysfs.c
··· 777 777 } 778 778 779 779 /** 780 - * blk_release_queue: - release a &struct request_queue when it is no longer needed 781 - * @kobj: the kobj belonging to the request queue to be released 780 + * __blk_release_queue - release a request queue when it is no longer needed 781 + * @work: pointer to the release_work member of the request queue to be released 782 782 * 783 783 * Description: 784 - * blk_release_queue is the pair to blk_init_queue() or 785 - * blk_queue_make_request(). It should be called when a request queue is 786 - * being released; typically when a block device is being de-registered. 787 - * Currently, its primary task it to free all the &struct request 788 - * structures that were allocated to the queue and the queue itself. 784 + * blk_release_queue is the counterpart of blk_init_queue(). It should be 785 + * called when a request queue is being released; typically when a block 786 + * device is being de-registered. Its primary task it to free the queue 787 + * itself. 789 788 * 790 - * Note: 789 + * Notes: 791 790 * The low level driver must have finished any outstanding requests first 792 791 * via blk_cleanup_queue(). 793 - **/ 794 - static void blk_release_queue(struct kobject *kobj) 792 + * 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 = 797 - container_of(kobj, struct request_queue, kobj); 798 + struct request_queue *q = container_of(work, typeof(*q), release_work); 798 799 799 800 if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags)) 800 801 blk_stat_remove_callback(q, q->poll_cb); ··· 833 832 834 833 ida_simple_remove(&blk_queue_ida, q->id); 835 834 call_rcu(&q->rcu_head, blk_free_queue_rcu); 835 + } 836 + 837 + static void blk_release_queue(struct kobject *kobj) 838 + { 839 + struct request_queue *q = 840 + container_of(kobj, struct request_queue, kobj); 841 + 842 + INIT_WORK(&q->release_work, __blk_release_queue); 843 + schedule_work(&q->release_work); 836 844 } 837 845 838 846 static const struct sysfs_ops queue_sysfs_ops = {
+2
include/linux/blkdev.h
··· 586 586 587 587 size_t cmd_size; 588 588 void *rq_alloc_data; 589 + 590 + struct work_struct release_work; 589 591 }; 590 592 591 593 #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */