diff options
author | Keith Busch <keith.busch@intel.com> | 2015-11-20 18:38:13 +0300 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-11-20 18:38:13 +0300 |
commit | 604e8c8da8854351496215d269c3fa93859e3fee (patch) | |
tree | 6d3860193ac4eba815623aebaf342161542d4e62 | |
parent | 2fde0e482db2b43bb4ed0e9aebfbe78ebcbbf5a6 (diff) | |
download | linux-604e8c8da8854351496215d269c3fa93859e3fee.tar.xz |
NVMe: reap completion entries when deleting queue
Make sure that there are no unprocesssed entries on a completion
queue before deleting it, and check for validity of the CQ
door bell before writing completions to it.
This fixes problems with doing a sysfs reset of the device while
it's handling IO.
Tested-by: Jon Derrick <jonathan.derrick@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/nvme/host/pci.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 394fd1631cd0..930042fa2d69 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -968,7 +968,8 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag) if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return; - writel(head, nvmeq->q_db + nvmeq->dev->db_stride); + if (likely(nvmeq->cq_vector >= 0)) + writel(head, nvmeq->q_db + nvmeq->dev->db_stride); nvmeq->cq_head = head; nvmeq->cq_phase = phase; @@ -2787,6 +2788,10 @@ static void nvme_del_queue_end(struct nvme_queue *nvmeq) { struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx; nvme_put_dq(dq); + + spin_lock_irq(&nvmeq->q_lock); + nvme_process_cq(nvmeq); + spin_unlock_irq(&nvmeq->q_lock); } static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode, |