aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <jsmart2021@gmail.com>2017-10-18 17:33:59 -0400
committerChristoph Hellwig <hch@lst.de>2017-10-19 03:16:12 -0400
commitf9cf2a64912d67c9cf49c316a0a0ada0ea7ed1da (patch)
treeda4512b8c99a0924534dacbf9706aac0b501609a
parent17c4dc6eb7e1b2fb1ce6a52467e3be635224606e (diff)
nvmet: synchronize sqhd update
In testing target io in read write mix, we did indeed get into cases where sqhd didn't update properly and slowly missed enough updates to shutdown the queue. Protect the updating sqhd by using cmpxchg, and for that turn the sqhd field into a u32 so that cmpxchg works on it for all architectures. Signed-off-by: James Smart <james.smart@broadcom.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/nvme/target/core.c15
-rw-r--r--drivers/nvme/target/nvmet.h2
2 files changed, 13 insertions, 4 deletions
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 1b208beeef50..645ba7eee35d 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -387,12 +387,21 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
387 387
388static void __nvmet_req_complete(struct nvmet_req *req, u16 status) 388static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
389{ 389{
390 u32 old_sqhd, new_sqhd;
391 u16 sqhd;
392
390 if (status) 393 if (status)
391 nvmet_set_status(req, status); 394 nvmet_set_status(req, status);
392 395
393 if (req->sq->size) 396 if (req->sq->size) {
394 req->sq->sqhd = (req->sq->sqhd + 1) % req->sq->size; 397 do {
395 req->rsp->sq_head = cpu_to_le16(req->sq->sqhd); 398 old_sqhd = req->sq->sqhd;
399 new_sqhd = (old_sqhd + 1) % req->sq->size;
400 } while (cmpxchg(&req->sq->sqhd, old_sqhd, new_sqhd) !=
401 old_sqhd);
402 }
403 sqhd = req->sq->sqhd & 0x0000FFFF;
404 req->rsp->sq_head = cpu_to_le16(sqhd);
396 req->rsp->sq_id = cpu_to_le16(req->sq->qid); 405 req->rsp->sq_id = cpu_to_le16(req->sq->qid);
397 req->rsp->command_id = req->cmd->common.command_id; 406 req->rsp->command_id = req->cmd->common.command_id;
398 407
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 7b8e20adf760..87e429bfcd8a 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -74,7 +74,7 @@ struct nvmet_sq {
74 struct percpu_ref ref; 74 struct percpu_ref ref;
75 u16 qid; 75 u16 qid;
76 u16 size; 76 u16 size;
77 u16 sqhd; 77 u32 sqhd;
78 struct completion free_done; 78 struct completion free_done;
79 struct completion confirm_done; 79 struct completion confirm_done;
80}; 80};