diff options
| author | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2012-08-07 15:56:23 -0400 |
|---|---|---|
| committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2012-08-07 15:56:23 -0400 |
| commit | a09115b23e2002bb35b7bfd337683f00875671ec (patch) | |
| tree | 1335ed44723c27fe0fd9ca221915b08fba4fbec8 | |
| parent | 9e866774aab5d2654b0fa8f97890f68913f05700 (diff) | |
NVMe: Cancel outstanding IOs on queue deletion
If the device is hot-unplugged while there are active commands, we should
time out the I/Os so that upper layers don't just see the I/Os disappear.
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
| -rw-r--r-- | drivers/block/nvme.c | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c index 214037055e2a..f9ad514c9227 100644 --- a/drivers/block/nvme.c +++ b/drivers/block/nvme.c | |||
| @@ -868,6 +868,33 @@ static int nvme_set_features(struct nvme_dev *dev, unsigned fid, | |||
| 868 | return nvme_submit_admin_cmd(dev, &c, result); | 868 | return nvme_submit_admin_cmd(dev, &c, result); |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | /** | ||
| 872 | * nvme_cancel_ios - Cancel outstanding I/Os | ||
| 873 | * @queue: The queue to cancel I/Os on | ||
| 874 | * @timeout: True to only cancel I/Os which have timed out | ||
| 875 | */ | ||
| 876 | static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout) | ||
| 877 | { | ||
| 878 | int depth = nvmeq->q_depth - 1; | ||
| 879 | struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); | ||
| 880 | unsigned long now = jiffies; | ||
| 881 | int cmdid; | ||
| 882 | |||
| 883 | for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) { | ||
| 884 | void *ctx; | ||
| 885 | nvme_completion_fn fn; | ||
| 886 | static struct nvme_completion cqe = { | ||
| 887 | .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, | ||
| 888 | }; | ||
| 889 | |||
| 890 | if (timeout && !time_after(now, info[cmdid].timeout)) | ||
| 891 | continue; | ||
| 892 | dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid); | ||
| 893 | ctx = cancel_cmdid(nvmeq, cmdid, &fn); | ||
| 894 | fn(nvmeq->dev, ctx, &cqe); | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 871 | static void nvme_free_queue_mem(struct nvme_queue *nvmeq) | 898 | static void nvme_free_queue_mem(struct nvme_queue *nvmeq) |
| 872 | { | 899 | { |
| 873 | dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), | 900 | dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), |
| @@ -882,6 +909,10 @@ static void nvme_free_queue(struct nvme_dev *dev, int qid) | |||
| 882 | struct nvme_queue *nvmeq = dev->queues[qid]; | 909 | struct nvme_queue *nvmeq = dev->queues[qid]; |
| 883 | int vector = dev->entry[nvmeq->cq_vector].vector; | 910 | int vector = dev->entry[nvmeq->cq_vector].vector; |
| 884 | 911 | ||
| 912 | spin_lock_irq(&nvmeq->q_lock); | ||
| 913 | nvme_cancel_ios(nvmeq, false); | ||
| 914 | spin_unlock_irq(&nvmeq->q_lock); | ||
| 915 | |||
| 885 | irq_set_affinity_hint(vector, NULL); | 916 | irq_set_affinity_hint(vector, NULL); |
| 886 | free_irq(vector, nvmeq); | 917 | free_irq(vector, nvmeq); |
| 887 | 918 | ||
| @@ -1236,26 +1267,6 @@ static const struct block_device_operations nvme_fops = { | |||
| 1236 | .compat_ioctl = nvme_ioctl, | 1267 | .compat_ioctl = nvme_ioctl, |
| 1237 | }; | 1268 | }; |
| 1238 | 1269 | ||
| 1239 | static void nvme_timeout_ios(struct nvme_queue *nvmeq) | ||
| 1240 | { | ||
| 1241 | int depth = nvmeq->q_depth - 1; | ||
| 1242 | struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); | ||
| 1243 | unsigned long now = jiffies; | ||
| 1244 | int cmdid; | ||
| 1245 | |||
| 1246 | for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) { | ||
| 1247 | void *ctx; | ||
| 1248 | nvme_completion_fn fn; | ||
| 1249 | static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, }; | ||
| 1250 | |||
| 1251 | if (!time_after(now, info[cmdid].timeout)) | ||
| 1252 | continue; | ||
| 1253 | dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid); | ||
| 1254 | ctx = cancel_cmdid(nvmeq, cmdid, &fn); | ||
| 1255 | fn(nvmeq->dev, ctx, &cqe); | ||
| 1256 | } | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | static void nvme_resubmit_bios(struct nvme_queue *nvmeq) | 1270 | static void nvme_resubmit_bios(struct nvme_queue *nvmeq) |
| 1260 | { | 1271 | { |
| 1261 | while (bio_list_peek(&nvmeq->sq_cong)) { | 1272 | while (bio_list_peek(&nvmeq->sq_cong)) { |
| @@ -1287,7 +1298,7 @@ static int nvme_kthread(void *data) | |||
| 1287 | spin_lock_irq(&nvmeq->q_lock); | 1298 | spin_lock_irq(&nvmeq->q_lock); |
| 1288 | if (nvme_process_cq(nvmeq)) | 1299 | if (nvme_process_cq(nvmeq)) |
| 1289 | printk("process_cq did something\n"); | 1300 | printk("process_cq did something\n"); |
| 1290 | nvme_timeout_ios(nvmeq); | 1301 | nvme_cancel_ios(nvmeq, true); |
| 1291 | nvme_resubmit_bios(nvmeq); | 1302 | nvme_resubmit_bios(nvmeq); |
| 1292 | spin_unlock_irq(&nvmeq->q_lock); | 1303 | spin_unlock_irq(&nvmeq->q_lock); |
| 1293 | } | 1304 | } |
| @@ -1549,8 +1560,6 @@ static int nvme_dev_remove(struct nvme_dev *dev) | |||
| 1549 | list_del(&dev->node); | 1560 | list_del(&dev->node); |
| 1550 | spin_unlock(&dev_list_lock); | 1561 | spin_unlock(&dev_list_lock); |
| 1551 | 1562 | ||
| 1552 | /* TODO: wait all I/O finished or cancel them */ | ||
| 1553 | |||
| 1554 | list_for_each_entry_safe(ns, next, &dev->namespaces, list) { | 1563 | list_for_each_entry_safe(ns, next, &dev->namespaces, list) { |
| 1555 | list_del(&ns->list); | 1564 | list_del(&ns->list); |
| 1556 | del_gendisk(ns->disk); | 1565 | del_gendisk(ns->disk); |
