diff options
| -rw-r--r-- | block/blk-mq-sysfs.c | 6 | ||||
| -rw-r--r-- | block/blk-mq.c | 6 | ||||
| -rw-r--r-- | block/blk-sysfs.c | 11 | ||||
| -rw-r--r-- | include/linux/blk-mq.h | 1 | 
4 files changed, 21 insertions, 3 deletions
| diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c index ed5217867555..371d8800b48a 100644 --- a/block/blk-mq-sysfs.c +++ b/block/blk-mq-sysfs.c @@ -402,6 +402,12 @@ static void blk_mq_sysfs_init(struct request_queue *q)  	}  } +/* see blk_register_queue() */ +void blk_mq_finish_init(struct request_queue *q) +{ +	percpu_ref_switch_to_percpu(&q->mq_usage_counter); +} +  int blk_mq_register_disk(struct gendisk *disk)  {  	struct device *dev = disk_to_dev(disk); diff --git a/block/blk-mq.c b/block/blk-mq.c index d85fe01c44ef..38f4a165640d 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1795,8 +1795,12 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)  	if (!q)  		goto err_hctxs; +	/* +	 * Init percpu_ref in atomic mode so that it's faster to shutdown. +	 * See blk_register_queue() for details. +	 */  	if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release, -			    0, GFP_KERNEL)) +			    PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))  		goto err_map;  	setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 17f5c84ce7bf..521ae9089c50 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -551,12 +551,19 @@ int blk_register_queue(struct gendisk *disk)  		return -ENXIO;  	/* -	 * Initialization must be complete by now.  Finish the initial -	 * bypass from queue allocation. +	 * SCSI probing may synchronously create and destroy a lot of +	 * request_queues for non-existent devices.  Shutting down a fully +	 * functional queue takes measureable wallclock time as RCU grace +	 * periods are involved.  To avoid excessive latency in these +	 * cases, a request_queue starts out in a degraded mode which is +	 * faster to shut down and is made fully functional here as +	 * request_queues for non-existent devices never get registered.  	 */  	if (!blk_queue_init_done(q)) {  		queue_flag_set_unlocked(QUEUE_FLAG_INIT_DONE, q);  		blk_queue_bypass_end(q); +		if (q->mq_ops) +			blk_mq_finish_init(q);  	}  	ret = blk_trace_init_sysfs(dev); diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index a1e31f274fcd..c13a0c09faea 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -140,6 +140,7 @@ enum {  };  struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); +void blk_mq_finish_init(struct request_queue *q);  int blk_mq_register_disk(struct gendisk *);  void blk_mq_unregister_disk(struct gendisk *); | 
