[PATCH v8 03/10] block: support nesting for blk-mq flag QUEUE_FLAG_SAME_FORCE
Nilay Shroff <[email protected]>
| Newsgroups | org.infradead.lists.linux-nvme |
|---|---|
| Message-ID | <[email protected]> |
QUEUE_FLAG_SAME_FORCE is currently used when setting rq_affinity through sysfs as well as by UFS mediatek driver while configuring scsi parameters. A subsequent patch adding a latency-based I/O policy for NVMe multipath will also use this flag. With multiple users able to set and clear QUEUE_FLAG_SAME_FORCE, the flag needs to support nesting so that one user clearing the flag does not inadvertently disable it for another user. Add a nesting counter, q->same_force_depth, for QUEUE_FLAG_SAME_FORCE. The flag is set when the first user acquires it and the nesting counter is incremented for each subsequent user. Similarly, each user releases its reference by decrementing the counter. The flag is cleared only when the last user releases it and the counter reaches zero. Preserve the existing sysfs rq_affinity semantics with a new q->same_force_sysfs flag. When userspace enables QUEUE_FLAG_SAME_FORCE by writing 2 to rq_affinity, mark q->same_force_sysfs as set and increment q->same_force_depth by one. Subsequent writes of 2 to rq_affinity while q->same_force_sysfs is already set are ignored, so repeated writes of 2 from userspace do not increase q->same_force_depth. Similarly, writing 0 or 1 decrements the q->same_force_depth and if nesting counter reached to 0 then clears the QUEUE_FLAG_SAME_FORCE. This ensures that multiple writes of 2 to rq_affinity do not require multiple writes of 0 or 1. This change ensures that sysfs interface retains its existing set/clear semantics while also allowing other kernel users to hold or release QUEUE_FLAG_SAME_FORCE. Added two new APIs blk_mq_same_force_set() and blk_mq_same_force_clear() to set and clear QUEUE_FLAG_SAME_FORCE respectively. Also, updated existing call paths using these new APIs which toggles QUEUE_FLAG_SAME_FORCE. Cc: Peter Wang <[email protected]> Cc: Chaotian Jing <[email protected]> Cc: Stanley Jhu <[email protected]> Cc: [email protected] Signed-off-by: Nilay Shroff <[email protected]> --- block/blk-mq.c | 41 +++++++++++++++++++++++++++++++++ block/blk-sysfs.c | 6 ++--- drivers/ufs/host/ufs-mediatek.c | 2 +- include/linux/blk-mq.h | 2 ++ include/linux/blkdev.h | 3 +++ 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 38922209a24f..17e8befb02bc 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -360,6 +360,47 @@ void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set) } EXPORT_SYMBOL_GPL(blk_mq_unquiesce_tagset); +void blk_mq_same_force_set(struct request_queue *q, bool from_sysfs) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&q->queue_lock, flags); + + if (from_sysfs) { + if (q->same_force_sysfs) + goto unlock; + q->same_force_sysfs = true; + } + + if (!q->same_force_depth++) + blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, q); +unlock: + spin_unlock_irqrestore(&q->queue_lock, flags); +} +EXPORT_SYMBOL_GPL(blk_mq_same_force_set); + +void blk_mq_same_force_clear(struct request_queue *q, bool from_sysfs) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&q->queue_lock, flags); + + if (from_sysfs) { + if (!q->same_force_sysfs) + goto unlock; + q->same_force_sysfs = false; + } + + if (WARN_ON_ONCE(q->same_force_depth <= 0)) + goto unlock; + + if (!--q->same_force_depth) + blk_queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q); +unlock: + spin_unlock_irqrestore(&q->queue_lock, flags); +} +EXPORT_SYMBOL_GPL(blk_mq_same_force_clear); + void blk_mq_wake_waiters(struct request_queue *q) { struct blk_mq_hw_ctx *hctx; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 520972676ab4..a3ec8ffab1ee 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -497,13 +497,13 @@ queue_rq_affinity_store(struct gendisk *disk, const char *page, size_t count) */ if (val == 2) { blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, q); - blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, q); + blk_mq_same_force_set(q, true); } else if (val == 1) { blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, q); - blk_queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q); + blk_mq_same_force_clear(q, true); } else if (val == 0) { blk_queue_flag_clear(QUEUE_FLAG_SAME_COMP, q); - blk_queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q); + blk_mq_same_force_clear(q, true); } #endif return ret; diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 3991a51263a6..8d80ac6fb5d2 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -2311,7 +2311,7 @@ static void ufs_mtk_config_scsi_dev(struct scsi_device *sdev) dev_dbg(hba->dev, "lu %llu scsi device configured", sdev->lun); if (sdev->lun == 2) - blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, sdev->request_queue); + blk_mq_same_force_set(sdev->request_queue, false); } /* diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 3956909764bf..30be3eb5a37b 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -943,6 +943,8 @@ void blk_mq_wait_quiesce_done(struct blk_mq_tag_set *set); void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set); void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set); void blk_mq_unquiesce_queue(struct request_queue *q); +void blk_mq_same_force_set(struct request_queue *q, bool from_sysfs); +void blk_mq_same_force_clear(struct request_queue *q, bool from_sysfs); void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs); void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async); void blk_mq_run_hw_queues(struct request_queue *q, bool async); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9213a5716f95..32d0fb47d73c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -529,6 +529,9 @@ struct request_queue { int quiesce_depth; + int same_force_depth; + bool same_force_sysfs; + struct gendisk *disk; /* -- 2.53.0