mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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 b425e50492
("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>
This commit is contained in:
parent
63f700aab4
commit
dc9edc44de
@ -777,24 +777,25 @@ static void blk_free_queue_rcu(struct rcu_head *rcu_head)
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_release_queue: - release a &struct request_queue when it is no longer needed
|
||||
* @kobj: the kobj belonging to the request queue to be released
|
||||
* __blk_release_queue - release a request queue when it is no longer needed
|
||||
* @work: pointer to the release_work member of the request queue to be released
|
||||
*
|
||||
* Description:
|
||||
* blk_release_queue is the pair to blk_init_queue() or
|
||||
* blk_queue_make_request(). It should be called when a request queue is
|
||||
* being released; typically when a block device is being de-registered.
|
||||
* Currently, its primary task it to free all the &struct request
|
||||
* structures that were allocated to the queue and the queue itself.
|
||||
* blk_release_queue is the counterpart of blk_init_queue(). It should be
|
||||
* called when a request queue is being released; typically when a block
|
||||
* device is being de-registered. Its primary task it to free the queue
|
||||
* itself.
|
||||
*
|
||||
* Note:
|
||||
* Notes:
|
||||
* The low level driver must have finished any outstanding requests first
|
||||
* via blk_cleanup_queue().
|
||||
**/
|
||||
static void blk_release_queue(struct kobject *kobj)
|
||||
*
|
||||
* Although blk_release_queue() may be called with preemption disabled,
|
||||
* __blk_release_queue() may sleep.
|
||||
*/
|
||||
static void __blk_release_queue(struct work_struct *work)
|
||||
{
|
||||
struct request_queue *q =
|
||||
container_of(kobj, struct request_queue, kobj);
|
||||
struct request_queue *q = container_of(work, typeof(*q), release_work);
|
||||
|
||||
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
|
||||
blk_stat_remove_callback(q, q->poll_cb);
|
||||
@ -834,6 +835,15 @@ static void blk_release_queue(struct kobject *kobj)
|
||||
call_rcu(&q->rcu_head, blk_free_queue_rcu);
|
||||
}
|
||||
|
||||
static void blk_release_queue(struct kobject *kobj)
|
||||
{
|
||||
struct request_queue *q =
|
||||
container_of(kobj, struct request_queue, kobj);
|
||||
|
||||
INIT_WORK(&q->release_work, __blk_release_queue);
|
||||
schedule_work(&q->release_work);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops queue_sysfs_ops = {
|
||||
.show = queue_attr_show,
|
||||
.store = queue_attr_store,
|
||||
|
@ -586,6 +586,8 @@ struct request_queue {
|
||||
|
||||
size_t cmd_size;
|
||||
void *rq_alloc_data;
|
||||
|
||||
struct work_struct release_work;
|
||||
};
|
||||
|
||||
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */
|
||||
|
Loading…
Reference in New Issue
Block a user