mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
Merge branch 'for-linus' of git://git.kernel.dk/linux-block
Pull block layer fix from Jens Axboe: "Just a single fix this week, fixing a regression introduced in this release. When we put the final reference to the queue, we may need to block. Ensure that we can safely do so. From Bart" * 'for-linus' of git://git.kernel.dk/linux-block: block: Fix a blk_exit_rl() regression
This commit is contained in:
commit
e78e4626d4
2 changed files with 24 additions and 12 deletions
|
@ -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
|
* __blk_release_queue - release a request queue when it is no longer needed
|
||||||
* @kobj: the kobj belonging to the request queue to be released
|
* @work: pointer to the release_work member of the request queue to be released
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* blk_release_queue is the pair to blk_init_queue() or
|
* blk_release_queue is the counterpart of blk_init_queue(). It should be
|
||||||
* blk_queue_make_request(). It should be called when a request queue is
|
* called when a request queue is being released; typically when a block
|
||||||
* being released; typically when a block device is being de-registered.
|
* device is being de-registered. Its primary task it to free the queue
|
||||||
* Currently, its primary task it to free all the &struct request
|
* itself.
|
||||||
* structures that were allocated to the queue and the queue itself.
|
|
||||||
*
|
*
|
||||||
* Note:
|
* Notes:
|
||||||
* The low level driver must have finished any outstanding requests first
|
* The low level driver must have finished any outstanding requests first
|
||||||
* via blk_cleanup_queue().
|
* 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 =
|
struct request_queue *q = container_of(work, typeof(*q), release_work);
|
||||||
container_of(kobj, struct request_queue, kobj);
|
|
||||||
|
|
||||||
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
|
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
|
||||||
blk_stat_remove_callback(q, q->poll_cb);
|
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);
|
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 = {
|
static const struct sysfs_ops queue_sysfs_ops = {
|
||||||
.show = queue_attr_show,
|
.show = queue_attr_show,
|
||||||
.store = queue_attr_store,
|
.store = queue_attr_store,
|
||||||
|
|
|
@ -586,6 +586,8 @@ struct request_queue {
|
||||||
|
|
||||||
size_t cmd_size;
|
size_t cmd_size;
|
||||||
void *rq_alloc_data;
|
void *rq_alloc_data;
|
||||||
|
|
||||||
|
struct work_struct release_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */
|
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */
|
||||||
|
|
Loading…
Reference in a new issue