Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e78e4626 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents cbfb7497 dc9edc44
Loading
Loading
Loading
Loading
+22 −12
Original line number Diff line number Diff line
@@ -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,
+2 −0
Original line number Diff line number Diff line
@@ -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 */