diff options
author | James Smart <jsmart2021@gmail.com> | 2017-10-18 14:33:59 -0700 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2017-10-19 09:16:12 +0200 |
commit | f9cf2a64912d67c9cf49c316a0a0ada0ea7ed1da (patch) | |
tree | da4512b8c99a0924534dacbf9706aac0b501609a /drivers/nvme/target/core.c | |
parent | 17c4dc6eb7e1b2fb1ce6a52467e3be635224606e (diff) | |
download | linux-f9cf2a64912d67c9cf49c316a0a0ada0ea7ed1da.tar.gz linux-f9cf2a64912d67c9cf49c316a0a0ada0ea7ed1da.tar.bz2 linux-f9cf2a64912d67c9cf49c316a0a0ada0ea7ed1da.zip |
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>
Diffstat (limited to 'drivers/nvme/target/core.c')
-rw-r--r-- | drivers/nvme/target/core.c | 15 |
1 files changed, 12 insertions, 3 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) static void __nvmet_req_complete(struct nvmet_req *req, u16 status) { + u32 old_sqhd, new_sqhd; + u16 sqhd; + if (status) nvmet_set_status(req, status); - if (req->sq->size) - req->sq->sqhd = (req->sq->sqhd + 1) % req->sq->size; - req->rsp->sq_head = cpu_to_le16(req->sq->sqhd); + if (req->sq->size) { + do { + old_sqhd = req->sq->sqhd; + new_sqhd = (old_sqhd + 1) % req->sq->size; + } while (cmpxchg(&req->sq->sqhd, old_sqhd, new_sqhd) != + old_sqhd); + } + sqhd = req->sq->sqhd & 0x0000FFFF; + req->rsp->sq_head = cpu_to_le16(sqhd); req->rsp->sq_id = cpu_to_le16(req->sq->qid); req->rsp->command_id = req->cmd->common.command_id; |