[PATCH 1/2] nvme: operate nvme_request->flags with atomic api

Ye Bin yebin at huaweicloud.com
Mon Jun 8 04:34:24 PDT 2026


From: Ye Bin <yebin10 at huawei.com>

This patch does not change any function. The nvme_request->flags is
converted to the unsigned long type and the atomic operation interface
is used. This prevents the status exception caused by concurrent
operations on flags. In addition, this is also a preparation for fixing
the problem that I/Os are processed twice in the done phase.

Signed-off-by: Ye Bin <yebin10 at huawei.com>
---
 drivers/nvme/host/apple.c     |  4 ++--
 drivers/nvme/host/core.c      |  7 ++++---
 drivers/nvme/host/fc.c        |  2 +-
 drivers/nvme/host/ioctl.c     |  4 ++--
 drivers/nvme/host/multipath.c | 12 ++++++------
 drivers/nvme/host/nvme.h      | 10 +++++-----
 drivers/nvme/host/pci.c       | 11 ++++++-----
 7 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c
index 423c9c628e7b..f669fecd5604 100644
--- a/drivers/nvme/host/apple.c
+++ b/drivers/nvme/host/apple.c
@@ -941,7 +941,7 @@ static enum blk_eh_timer_return apple_nvme_timeout(struct request *req)
 		if (blk_mq_request_started(req) &&
 		    !blk_mq_request_completed(req)) {
 			nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
-			nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+			set_bit(NVME_REQ_CANCELLED, &nvme_req(req)->flags);
 			blk_mq_complete_request(req);
 		}
 		return BLK_EH_DONE;
@@ -966,7 +966,7 @@ static enum blk_eh_timer_return apple_nvme_timeout(struct request *req)
 	 */
 	dev_warn(anv->dev, "I/O %d(aq:%d) timeout: resetting controller\n",
 		 req->tag, q->is_adminq);
-	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+	set_bit(NVME_REQ_CANCELLED, &nvme_req(req)->flags);
 	apple_nvme_disable(anv, false);
 	nvme_reset_ctrl(&anv->ctrl);
 	return BLK_EH_DONE;
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index dc388e24caad..c06f18dc5a65 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -533,7 +533,7 @@ bool nvme_cancel_request(struct request *req, void *data)
 		return true;
 
 	nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
-	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+	set_bit(NVME_REQ_CANCELLED, &nvme_req(req)->flags);
 	blk_mq_complete_request(req);
 	return true;
 }
@@ -790,7 +790,8 @@ bool __nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
 	 * sequence. until the controller will be LIVE, fail with
 	 * BLK_STS_RESOURCE so that they will be rescheduled.
 	 */
-	if (rq->q == ctrl->admin_q && (req->flags & NVME_REQ_USERCMD))
+	if (rq->q == ctrl->admin_q &&
+	    test_bit(NVME_REQ_USERCMD, &req->flags))
 		return false;
 
 	if (ctrl->ops->flags & NVME_F_FABRICS) {
@@ -1149,7 +1150,7 @@ int nvme_execute_rq(struct request *rq, bool at_head)
 	blk_status_t status;
 
 	status = blk_execute_rq(rq, at_head);
-	if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
+	if (test_bit(NVME_REQ_CANCELLED, &nvme_req(rq)->flags))
 		return -EINTR;
 	if (nvme_req(rq)->status)
 		return nvme_req(rq)->status;
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index e4f4528fe2a2..f6e25ccc730b 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2420,7 +2420,7 @@ static bool nvme_fc_terminate_exchange(struct request *req, void *data)
 	struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
 	struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req);
 
-	op->nreq.flags |= NVME_REQ_CANCELLED;
+	set_bit(NVME_REQ_CANCELLED, &op->nreq.flags);
 	__nvme_fc_abort_op(ctrl, op);
 	return true;
 }
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 9597a87cf05d..62316da41521 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -108,7 +108,7 @@ static struct request *nvme_alloc_user_request(struct request_queue *q,
 	if (IS_ERR(req))
 		return req;
 	nvme_init_request(req, cmd);
-	nvme_req(req)->flags |= NVME_REQ_USERCMD;
+	set_bit(NVME_REQ_USERCMD, &nvme_req(req)->flags);
 	return req;
 }
 
@@ -416,7 +416,7 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
 	struct io_uring_cmd *ioucmd = req->end_io_data;
 	struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd);
 
-	if (nvme_req(req)->flags & NVME_REQ_CANCELLED) {
+	if (test_bit(NVME_REQ_CANCELLED, &nvme_req(req)->flags)) {
 		pdu->status = -EINTR;
 	} else {
 		pdu->status = nvme_req(req)->status;
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 263161cb8ac0..7ac1b13e24cb 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -170,16 +170,16 @@ void nvme_mpath_start_request(struct request *rq)
 	struct gendisk *disk = ns->head->disk;
 
 	if ((READ_ONCE(ns->head->subsys->iopolicy) == NVME_IOPOLICY_QD) &&
-	    !(nvme_req(rq)->flags & NVME_MPATH_CNT_ACTIVE)) {
+	    !test_bit(NVME_MPATH_CNT_ACTIVE, &nvme_req(rq)->flags)) {
 		atomic_inc(&ns->ctrl->nr_active);
-		nvme_req(rq)->flags |= NVME_MPATH_CNT_ACTIVE;
+		set_bit(NVME_MPATH_CNT_ACTIVE, &nvme_req(rq)->flags);
 	}
 
 	if (!blk_queue_io_stat(disk->queue) || blk_rq_is_passthrough(rq) ||
-	    (nvme_req(rq)->flags & NVME_MPATH_IO_STATS))
+	    test_bit(NVME_MPATH_IO_STATS, &nvme_req(rq)->flags))
 		return;
 
-	nvme_req(rq)->flags |= NVME_MPATH_IO_STATS;
+	set_bit(NVME_MPATH_IO_STATS, &nvme_req(rq)->flags);
 	nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0, req_op(rq),
 						      jiffies);
 }
@@ -189,10 +189,10 @@ void nvme_mpath_end_request(struct request *rq)
 {
 	struct nvme_ns *ns = rq->q->queuedata;
 
-	if (nvme_req(rq)->flags & NVME_MPATH_CNT_ACTIVE)
+	if (test_bit(NVME_MPATH_CNT_ACTIVE, &nvme_req(rq)->flags))
 		atomic_dec_if_positive(&ns->ctrl->nr_active);
 
-	if (!(nvme_req(rq)->flags & NVME_MPATH_IO_STATS))
+	if (!test_bit(NVME_MPATH_IO_STATS, &nvme_req(rq)->flags))
 		return;
 	bdev_end_io_acct(ns->head->disk->part0, req_op(rq),
 			 blk_rq_bytes(rq) >> SECTOR_SHIFT,
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ccd5e05dac98..1059976b413b 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -243,8 +243,8 @@ struct nvme_request {
 	union nvme_result	result;
 	u8			genctr;
 	u8			retries;
-	u8			flags;
 	u16			status;
+	unsigned long		flags;
 #ifdef CONFIG_NVME_MULTIPATH
 	unsigned long		start_time;
 #endif
@@ -257,10 +257,10 @@ struct nvme_request {
 #define REQ_NVME_MPATH		REQ_DRV
 
 enum {
-	NVME_REQ_CANCELLED		= (1 << 0),
-	NVME_REQ_USERCMD		= (1 << 1),
-	NVME_MPATH_IO_STATS		= (1 << 2),
-	NVME_MPATH_CNT_ACTIVE		= (1 << 3),
+	NVME_REQ_CANCELLED		= 0,
+	NVME_REQ_USERCMD		= 1,
+	NVME_MPATH_IO_STATS		= 2,
+	NVME_MPATH_CNT_ACTIVE		= 3,
 };
 
 static inline struct nvme_request *nvme_req(struct request *req)
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 9fd04cd7c5cb..ab77973338b5 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -760,7 +760,7 @@ static inline bool nvme_pci_metadata_use_sgls(struct request *req)
 	if (!nvme_ctrl_meta_sgl_supported(&dev->ctrl))
 		return false;
 	return req->nr_integrity_segments > 1 ||
-		nvme_req(req)->flags & NVME_REQ_USERCMD;
+		test_bit(NVME_REQ_USERCMD, &nvme_req(req)->flags);
 }
 
 static inline enum nvme_use_sgl nvme_pci_use_sgls(struct nvme_dev *dev,
@@ -783,7 +783,7 @@ static inline enum nvme_use_sgl nvme_pci_use_sgls(struct nvme_dev *dev,
 		 *    only way to describe such a command in NVMe.
 		 */
 		if (req_phys_gap_mask(req) & (NVME_CTRL_PAGE_SIZE - 1) ||
-		    nvme_req(req)->flags & NVME_REQ_USERCMD ||
+		    test_bit(NVME_REQ_USERCMD, &nvme_req(req)->flags) ||
 		    req->nr_integrity_segments > 1)
 			return SGL_FORCED;
 		return SGL_SUPPORTED;
@@ -1303,7 +1303,8 @@ static blk_status_t nvme_pci_setup_meta_iter(struct request *req)
 	 * leverages this routine when that happens.
 	 */
 	if (!nvme_ctrl_meta_sgl_supported(&dev->ctrl) ||
-	    (entries == 1 && !(nvme_req(req)->flags & NVME_REQ_USERCMD))) {
+	    (entries == 1 &&
+	     !test_bit(NVME_REQ_USERCMD, &nvme_req(req)->flags))) {
 		iod->cmd.common.metadata = cpu_to_le64(iter.addr);
 		iod->meta_total_len = iter.len;
 		iod->meta_dma = iter.addr;
@@ -1909,7 +1910,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
 		dev_warn_ratelimited(dev->ctrl.device,
 			 "I/O tag %d (%04x) QID %d timeout, disable controller\n",
 			 req->tag, nvme_cid(req), nvmeq->qid);
-		nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+		set_bit(NVME_REQ_CANCELLED, &nvme_req(req)->flags);
 		nvme_dev_disable(dev, true);
 		return BLK_EH_DONE;
 	case NVME_CTRL_RESETTING:
@@ -1929,7 +1930,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
 			 "I/O tag %d (%04x) opcode %#x (%s) QID %d timeout, reset controller\n",
 			 req->tag, nvme_cid(req), opcode,
 			 nvme_opcode_str(nvmeq->qid, opcode), nvmeq->qid);
-		nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+		set_bit(NVME_REQ_CANCELLED, &nvme_req(req)->flags);
 		goto disable;
 	}
 
-- 
2.34.1




More information about the Linux-nvme mailing list