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

Commit 4a319a49 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-3.17/core' of git://git.kernel.dk/linux-block

Pull block core bits from Jens Axboe:
 "Small round this time, after the massive blk-mq dump for 3.16.  This
  pull request contains:

   - Fixes for max_sectors overflow in ioctls from Akinoby Mita.

   - Partition off-by-one bug fix in aix partitions from Dan Carpenter.

   - Various small partition cleanups from Fabian Frederick.

   - Fix for the block integrity code sometimes returning the wrong
     vector count from Gu Zheng.

   - Cleanup an re-org of the blk-mq queue enter/exit percpu counters
     from Tejun.  Dependent on the percpu pull for 3.17 (which was in
     the block tree too), that you have already pulled in.

   - A blkcg oops fix, also from Tejun"

* 'for-3.17/core' of git://git.kernel.dk/linux-block:
  partitions: aix.c: off by one bug
  blkcg: don't call into policy draining if root_blkg is already gone
  Revert "bio: modify __bio_add_page() to accept pages that don't start a new segment"
  bio: modify __bio_add_page() to accept pages that don't start a new segment
  block: fix SG_[GS]ET_RESERVED_SIZE ioctl when max_sectors is huge
  block: fix BLKSECTGET ioctl when max_sectors is greater than USHRT_MAX
  block/partitions/efi.c: kerneldoc fixing
  block/partitions/msdos.c: code clean-up
  block/partitions/amiga.c: replace nolevel printk by pr_err
  block/partitions/aix.c: replace count*size kzalloc by kcalloc
  bio-integrity: add "bip_max_vcnt" into struct bio_integrity_payload
  blk-mq: use percpu_ref for mq usage count
  blk-mq: collapse __blk_mq_drain_queue() into blk_mq_freeze_queue()
  blk-mq: decouble blk-mq freezing from generic bypassing
  block, blk-mq: draining can't be skipped even if bypass_depth was non-zero
  blk-mq: fix a memory ordering bug in blk_mq_queue_enter()
parents f0094b28 d97a86c1
Loading
Loading
Loading
Loading
+3 −9
Original line number Diff line number Diff line
@@ -70,8 +70,10 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
					  bs->bvec_integrity_pool);
		if (!bip->bip_vec)
			goto err;
		bip->bip_max_vcnt = bvec_nr_vecs(idx);
	} else {
		bip->bip_vec = bip->bip_inline_vecs;
		bip->bip_max_vcnt = inline_vecs;
	}

	bip->bip_slab = idx;
@@ -114,14 +116,6 @@ void bio_integrity_free(struct bio *bio)
}
EXPORT_SYMBOL(bio_integrity_free);

static inline unsigned int bip_integrity_vecs(struct bio_integrity_payload *bip)
{
	if (bip->bip_slab == BIO_POOL_NONE)
		return BIP_INLINE_VECS;

	return bvec_nr_vecs(bip->bip_slab);
}

/**
 * bio_integrity_add_page - Attach integrity metadata
 * @bio:	bio to update
@@ -137,7 +131,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
	struct bio_integrity_payload *bip = bio->bi_integrity;
	struct bio_vec *iv;

	if (bip->bip_vcnt >= bip_integrity_vecs(bip)) {
	if (bip->bip_vcnt >= bip->bip_max_vcnt) {
		printk(KERN_ERR "%s: bip_vec full\n", __func__);
		return 0;
	}
+8 −5
Original line number Diff line number Diff line
@@ -438,14 +438,17 @@ static void __blk_drain_queue(struct request_queue *q, bool drain_all)
 */
void blk_queue_bypass_start(struct request_queue *q)
{
	bool drain;

	spin_lock_irq(q->queue_lock);
	drain = !q->bypass_depth++;
	q->bypass_depth++;
	queue_flag_set(QUEUE_FLAG_BYPASS, q);
	spin_unlock_irq(q->queue_lock);

	if (drain) {
	/*
	 * Queues start drained.  Skip actual draining till init is
	 * complete.  This avoids lenghty delays during queue init which
	 * can happen many times during boot.
	 */
	if (blk_queue_init_done(q)) {
		spin_lock_irq(q->queue_lock);
		__blk_drain_queue(q, false);
		spin_unlock_irq(q->queue_lock);
@@ -511,7 +514,7 @@ void blk_cleanup_queue(struct request_queue *q)
	 * prevent that q->request_fn() gets invoked after draining finished.
	 */
	if (q->mq_ops) {
		blk_mq_drain_queue(q);
		blk_mq_freeze_queue(q);
		spin_lock_irq(lock);
	} else {
		spin_lock_irq(lock);
+29 −52
Original line number Diff line number Diff line
@@ -78,68 +78,47 @@ static void blk_mq_hctx_clear_pending(struct blk_mq_hw_ctx *hctx,

static int blk_mq_queue_enter(struct request_queue *q)
{
	while (true) {
		int ret;

	__percpu_counter_add(&q->mq_usage_counter, 1, 1000000);
	smp_wmb();

	/* we have problems freezing the queue if it's initializing */
	if (!blk_queue_dying(q) &&
	    (!blk_queue_bypass(q) || !blk_queue_init_done(q)))
		if (percpu_ref_tryget_live(&q->mq_usage_counter))
			return 0;

	__percpu_counter_add(&q->mq_usage_counter, -1, 1000000);

	spin_lock_irq(q->queue_lock);
	ret = wait_event_interruptible_lock_irq(q->mq_freeze_wq,
		!blk_queue_bypass(q) || blk_queue_dying(q),
		*q->queue_lock);
	/* inc usage with lock hold to avoid freeze_queue runs here */
	if (!ret && !blk_queue_dying(q))
		__percpu_counter_add(&q->mq_usage_counter, 1, 1000000);
	else if (blk_queue_dying(q))
		ret = -ENODEV;
	spin_unlock_irq(q->queue_lock);

		ret = wait_event_interruptible(q->mq_freeze_wq,
				!q->mq_freeze_depth || blk_queue_dying(q));
		if (blk_queue_dying(q))
			return -ENODEV;
		if (ret)
			return ret;
	}
}

static void blk_mq_queue_exit(struct request_queue *q)
{
	__percpu_counter_add(&q->mq_usage_counter, -1, 1000000);
	percpu_ref_put(&q->mq_usage_counter);
}

void blk_mq_drain_queue(struct request_queue *q)
static void blk_mq_usage_counter_release(struct percpu_ref *ref)
{
	while (true) {
		s64 count;

		spin_lock_irq(q->queue_lock);
		count = percpu_counter_sum(&q->mq_usage_counter);
		spin_unlock_irq(q->queue_lock);
	struct request_queue *q =
		container_of(ref, struct request_queue, mq_usage_counter);

		if (count == 0)
			break;
		blk_mq_start_hw_queues(q);
		msleep(10);
	}
	wake_up_all(&q->mq_freeze_wq);
}

/*
 * Guarantee no request is in use, so we can change any data structure of
 * the queue afterward.
 */
static void blk_mq_freeze_queue(struct request_queue *q)
void blk_mq_freeze_queue(struct request_queue *q)
{
	bool drain;

	spin_lock_irq(q->queue_lock);
	drain = !q->bypass_depth++;
	queue_flag_set(QUEUE_FLAG_BYPASS, q);
	q->mq_freeze_depth++;
	spin_unlock_irq(q->queue_lock);

	if (drain)
		blk_mq_drain_queue(q);
	percpu_ref_kill(&q->mq_usage_counter);
	blk_mq_run_queues(q, false);
	wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->mq_usage_counter));
}

static void blk_mq_unfreeze_queue(struct request_queue *q)
@@ -147,15 +126,14 @@ static void blk_mq_unfreeze_queue(struct request_queue *q)
	bool wake = false;

	spin_lock_irq(q->queue_lock);
	if (!--q->bypass_depth) {
		queue_flag_clear(QUEUE_FLAG_BYPASS, q);
		wake = true;
	}
	WARN_ON_ONCE(q->bypass_depth < 0);
	wake = !--q->mq_freeze_depth;
	WARN_ON_ONCE(q->mq_freeze_depth < 0);
	spin_unlock_irq(q->queue_lock);
	if (wake)
	if (wake) {
		percpu_ref_reinit(&q->mq_usage_counter);
		wake_up_all(&q->mq_freeze_wq);
	}
}

bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx)
{
@@ -1798,7 +1776,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
	if (!q)
		goto err_hctxs;

	if (percpu_counter_init(&q->mq_usage_counter, 0))
	if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release))
		goto err_map;

	setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
@@ -1891,7 +1869,7 @@ void blk_mq_free_queue(struct request_queue *q)
	blk_mq_exit_hw_queues(q, set, set->nr_hw_queues);
	blk_mq_free_hw_queues(q, set);

	percpu_counter_destroy(&q->mq_usage_counter);
	percpu_ref_exit(&q->mq_usage_counter);

	free_percpu(q->queue_ctx);
	kfree(q->queue_hw_ctx);
@@ -2050,8 +2028,7 @@ static int __init blk_mq_init(void)
{
	blk_mq_cpu_init();

	/* Must be called after percpu_counter_hotcpu_callback() */
	hotcpu_notifier(blk_mq_queue_reinit_notify, -10);
	hotcpu_notifier(blk_mq_queue_reinit_notify, 0);

	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct blk_mq_ctx {
void __blk_mq_complete_request(struct request *rq);
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
void blk_mq_init_flush(struct request_queue *q);
void blk_mq_drain_queue(struct request_queue *q);
void blk_mq_freeze_queue(struct request_queue *q);
void blk_mq_free_queue(struct request_queue *q);
void blk_mq_clone_flush_request(struct request *flush_rq,
		struct request *orig_rq);
+1 −1
Original line number Diff line number Diff line
@@ -554,8 +554,8 @@ int blk_register_queue(struct gendisk *disk)
	 * Initialization must be complete by now.  Finish the initial
	 * bypass from queue allocation.
	 */
	blk_queue_bypass_end(q);
	queue_flag_set_unlocked(QUEUE_FLAG_INIT_DONE, q);
	blk_queue_bypass_end(q);

	ret = blk_trace_init_sysfs(dev);
	if (ret)
Loading