Skip to content

Commit dc9edc4

Browse files
Bart Van Asscheaxboe
authored andcommitted
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 b425e50 ("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>
1 parent 63f700a commit dc9edc4

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

block/blk-sysfs.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -777,24 +777,25 @@ static void blk_free_queue_rcu(struct rcu_head *rcu_head)
777777
}
778778

779779
/**
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
782782
*
783783
* 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.
789788
*
790-
* Note:
789+
* Notes:
791790
* The low level driver must have finished any outstanding requests first
792791
* 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)
795797
{
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);
798799

799800
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
800801
blk_stat_remove_callback(q, q->poll_cb);
@@ -834,6 +835,15 @@ static void blk_release_queue(struct kobject *kobj)
834835
call_rcu(&q->rcu_head, blk_free_queue_rcu);
835836
}
836837

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+
837847
static const struct sysfs_ops queue_sysfs_ops = {
838848
.show = queue_attr_show,
839849
.store = queue_attr_store,

include/linux/blkdev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,8 @@ struct request_queue {
586586

587587
size_t cmd_size;
588588
void *rq_alloc_data;
589+
590+
struct work_struct release_work;
589591
};
590592

591593
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */

0 commit comments

Comments
 (0)