diff mbox series

scsi: ufs: Fix the polling implementation

Message ID 20221114233042.3199381-1-bvanassche@acm.org
State New
Headers show
Series scsi: ufs: Fix the polling implementation | expand

Commit Message

Bart Van Assche Nov. 14, 2022, 11:30 p.m. UTC
Certain code in the block layer assumes that requests submitted on a
polling queue (HCTX_TYPE_POLL) are completed in thread context. Hence
this patch that modifies ufshcd_poll() such that only requests are
completed for the hardware queue that is being examined instead of all
hardware queues. The block layer code that makes this assumption is the
bio caching code. From block/bio.c:

    If REQ_ALLOC_CACHE is set, the final put of the bio MUST be done
    from process context, not hard/soft IRQ.

The REQ_ALLOC_CACHE flag is set for polled I/O (REQ_POLLED) since
kernel v5.15. See also commit be4d234d7aeb ("bio: add allocation cache
abstraction").

Fixes: eaab9b573054 ("scsi: ufs: Implement polling support")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 drivers/ufs/core/ufshcd.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

Comments

Bart Van Assche Nov. 15, 2022, 11:23 p.m. UTC | #1
On 11/14/22 15:30, Bart Van Assche wrote:
> Certain code in the block layer assumes that requests submitted on a
> polling queue (HCTX_TYPE_POLL) are completed in thread context. Hence
> this patch that modifies ufshcd_poll() such that only requests are
> completed for the hardware queue that is being examined instead of all
> hardware queues. The block layer code that makes this assumption is the
> bio caching code. From block/bio.c:
> 
>      If REQ_ALLOC_CACHE is set, the final put of the bio MUST be done
>      from process context, not hard/soft IRQ.
> 
> The REQ_ALLOC_CACHE flag is set for polled I/O (REQ_POLLED) since
> kernel v5.15. See also commit be4d234d7aeb ("bio: add allocation cache
> abstraction").

Please drop this patch - I plan to send an improved version later.

Bart.
diff mbox series

Patch

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 05925939af35..f80d09aea669 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -5430,6 +5430,7 @@  static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num)
 	struct ufs_hba *hba = shost_priv(shost);
 	unsigned long completed_reqs, flags;
 	u32 tr_doorbell;
+	int tag;
 
 	spin_lock_irqsave(&hba->outstanding_lock, flags);
 	tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
@@ -5437,6 +5438,18 @@  static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num)
 	WARN_ONCE(completed_reqs & ~hba->outstanding_reqs,
 		  "completed: %#lx; outstanding: %#lx\n", completed_reqs,
 		  hba->outstanding_reqs);
+	for_each_set_bit(tag, &completed_reqs, hba->nutrs) {
+		struct ufshcd_lrb *lrbp = &hba->lrb[tag];
+
+		if (lrbp->cmd) {
+			struct request *rq = scsi_cmd_to_rq(lrbp->cmd);
+			u32 unique_tag = blk_mq_unique_tag(rq);
+			u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag);
+
+			if (hwq != queue_num)
+				__clear_bit(tag, &completed_reqs);
+		}
+	}
 	hba->outstanding_reqs &= ~completed_reqs;
 	spin_unlock_irqrestore(&hba->outstanding_lock, flags);