[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.