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>
This commit is contained in:
James Smart 2017-10-18 14:33:59 -07:00 committed by Christoph Hellwig
parent 17c4dc6eb7
commit f9cf2a6491
2 changed files with 13 additions and 4 deletions

View File

@ -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) static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
{ {
u32 old_sqhd, new_sqhd;
u16 sqhd;
if (status) if (status)
nvmet_set_status(req, status); nvmet_set_status(req, status);
if (req->sq->size) if (req->sq->size) {
req->sq->sqhd = (req->sq->sqhd + 1) % req->sq->size; do {
req->rsp->sq_head = cpu_to_le16(req->sq->sqhd); 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->sq_id = cpu_to_le16(req->sq->qid);
req->rsp->command_id = req->cmd->common.command_id; req->rsp->command_id = req->cmd->common.command_id;

View File

@ -74,7 +74,7 @@ struct nvmet_sq {
struct percpu_ref ref; struct percpu_ref ref;
u16 qid; u16 qid;
u16 size; u16 size;
u16 sqhd; u32 sqhd;
struct completion free_done; struct completion free_done;
struct completion confirm_done; struct completion confirm_done;
}; };