NVMe: Namespace removal simplifications
Subsystems (2)
PATCH 1/2 NVMe: Namespace removal simplifications
This liberates namespace removal from the device, allowing gendisk references to be closed independent of the nvme controller reference count.
--- drivers/block/nvme-core.c | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-)
drivers/block/nvme-core.c +10 -32
@@ -1943,6 +1943,7 @@ static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,#define nvme_compat_ioctl NULL#endif +static void nvme_free_dev (struct kref *kref);static void nvme_free_ns (struct kref *kref) { struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
@@ -1951,6 +1952,7 @@ static void nvme_free_ns(struct kref *kref) ns->disk->private_data =NULL ;spin_unlock (&dev_list_lock); +kref_put (&ns->dev->kref, nvme_free_dev);put_disk (ns->disk);kfree (ns); }
@@ -1966,22 +1968,14 @@ static int nvme_open(struct block_device *bdev, fmode_t mode) ret = -ENXIO ; else if (!kref_get_unless_zero(&ns->kref)) ret = -ENXIO ; - else if (!kref_get_unless_zero(&ns->dev->kref)) { -kref_put (&ns->kref, nvme_free_ns); - ret = -ENXIO ; - }spin_unlock (&dev_list_lock);return ret; } -static void nvme_free_dev (struct kref *kref);static void nvme_release (struct gendisk *disk,fmode_t mode) {struct nvme_ns *ns = disk->private_data; -struct nvme_dev *dev = ns->dev; - -kref_put (&dev->kref, nvme_free_dev);kref_put (&ns->kref, nvme_free_ns); }
@@ -2179,6 +2173,7 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)if (nvme_revalidate_disk (ns->disk)) goto out_free_disk; +kref_get (&dev->kref);add_disk (ns->disk);if (ns->ms) {struct block_device *bd =bdget_disk (ns->disk,0 );
@@ -2374,12 +2369,6 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)return result; } -static void nvme_free_namespace (struct nvme_ns *ns) -{ -list_del (&ns->list); -kref_put (&ns->kref, nvme_free_ns); -} -static int ns_cmp (void *priv,struct list_head *a,struct list_head *b) { struct nvme_ns *nsa = container_of(a, struct nvme_ns, list);
@@ -2421,7 +2410,9 @@ static void nvme_ns_remove(struct nvme_ns *ns)if (kill || !blk_queue_dying (ns->queue)) {blk_mq_abort_requeue_list (ns->queue);blk_cleanup_queue (ns->queue); - } + } +list_del_init (&ns->list); +kref_put (&ns->kref, nvme_free_ns); }static void nvme_scan_namespaces (struct nvme_dev *dev,unsigned nn)
@@ -2432,18 +2423,14 @@ static void nvme_scan_namespaces(struct nvme_dev *dev, unsigned nn)for (i =1 ; i <= nn; i++) { ns =nvme_find_ns (dev, i);if (ns) { -if (revalidate_disk (ns->disk)) { +if (revalidate_disk (ns->disk))nvme_ns_remove (ns); -nvme_free_namespace (ns); - } }else nvme_alloc_ns (dev, i); }list_for_each_entry_safe (ns, next, &dev->namespaces, list) { -if (ns->ns_id > nn) { +if (ns->ns_id > nn)nvme_ns_remove (ns); -nvme_free_namespace (ns); - } }list_sort (NULL , &dev->namespaces, ns_cmp); }
@@ -2833,9 +2820,9 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)static void nvme_dev_remove (struct nvme_dev *dev) { -struct nvme_ns *ns; +struct nvme_ns *ns, *next; -list_for_each_entry (ns, &dev->namespaces, list) +list_for_each_entry_safe (ns, next, &dev->namespaces, list)nvme_ns_remove (ns); }
@@ -2891,21 +2878,12 @@ static void nvme_release_instance(struct nvme_dev *dev)spin_unlock (&dev_list_lock); } -static void nvme_free_namespaces (struct nvme_dev *dev) -{ -struct nvme_ns *ns, *next; - -list_for_each_entry_safe (ns, next, &dev->namespaces, list) -nvme_free_namespace (ns); -} -static void nvme_free_dev (struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);put_device (dev->dev);put_device (dev->device); -nvme_free_namespaces (dev);nvme_release_instance (dev);if (dev->tagset.tags)blk_mq_free_tag_set (&dev->tagset);
Signature · 1 line
1.7.10.4
PATCH v2 2/2 NVMe: Simplify device resume on io queue failure
Releasing IO queues and disks was done in a work queue outside the controller resume context to delete namespaces if the controller failed after a resume from suspend. This is unnecessary since we can resume a device asynchronously.
This patch makes resume use probe_work so it can directly remove namespaces if the device is manageable but not IO capable. Since the deleting disks was the only reason we had the convoluted "reset_workfn", this patch removes that unnecessary indirection.
---v1->v2:
Removed unrelated nvme work_queue changes.
Merge conflict from the previous commit.
I'll also point out the new print here should satisfy Jon's case he brought up here:
http://lists.infradead.org/pipermail/linux-nvme/2015-September/002401.html
drivers/block/nvme-core.c | 34 ++++++---------------------------- include/linux/nvme.h | 1 - 2 files changed, 6 insertions(+), 29 deletions(-)
drivers/block/nvme-core.c +6 -28
@@ -1285,7 +1285,6 @@ static void nvme_abort_req(struct request *req)list_del_init (&dev->node);dev_warn (dev->dev,"I/O %d QID %d timeout, reset controller\n" , req->tag, nvmeq->qid); - dev->reset_workfn = nvme_reset_failed_dev;queue_work (nvme_workq, &dev->reset_work); out:spin_unlock_irqrestore (&dev_list_lock, flags);
@@ -2089,7 +2088,6 @@ static int nvme_kthread(void *data)dev_warn (dev->dev,"Failed status: %x, reset controller\n" ,readl (&dev->bar->csts)); - dev->reset_workfn = nvme_reset_failed_dev;queue_work (nvme_workq, &dev->reset_work);continue ; }
@@ -3025,14 +3023,6 @@ static int nvme_remove_dead_ctrl(void *arg)return 0 ; } -static void nvme_remove_disks (struct work_struct *ws) -{ - struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); - -nvme_free_queues (dev,1 ); -nvme_dev_remove (dev); -} -static int nvme_dev_resume (struct nvme_dev *dev) {int ret;
@@ -3041,10 +3031,9 @@ static int nvme_dev_resume(struct nvme_dev *dev)if (ret)return ret;if (dev->online_queues <2 ) { -spin_lock (&dev_list_lock); - dev->reset_workfn = nvme_remove_disks; -queue_work (nvme_workq, &dev->reset_work); -spin_unlock (&dev_list_lock); +dev_warn (dev->dev,"IO queues not created\n" ); +nvme_free_queues (dev,1 ); +nvme_dev_remove (dev); }else {nvme_unfreeze_queues (dev);nvme_dev_add (dev);
@@ -3091,12 +3080,6 @@ static void nvme_reset_failed_dev(struct work_struct *ws)nvme_dev_reset (dev); } -static void nvme_reset_workfn (struct work_struct *work) -{ - struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work); - dev->reset_workfn (work); -} -static int nvme_reset (struct nvme_dev *dev) {int ret = -EBUSY ;
@@ -3106,7 +3089,6 @@ static int nvme_reset(struct nvme_dev *dev)spin_lock (&dev_list_lock);if (!work_pending (&dev->reset_work)) { - dev->reset_workfn = nvme_reset_failed_dev;queue_work (nvme_workq, &dev->reset_work); ret =0 ; }
@@ -3159,8 +3141,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto free;INIT_LIST_HEAD (&dev->namespaces); - dev->reset_workfn = nvme_reset_failed_dev; -INIT_WORK (&dev->reset_work, nvme_reset_workfn); +INIT_WORK (&dev->reset_work, nvme_reset_failed_dev); dev->dev =get_device (&pdev->dev);pci_set_drvdata (pdev, dev); result =nvme_set_instance (dev);
@@ -3223,7 +3204,7 @@ static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)if (prepare)nvme_dev_shutdown (dev);else -nvme_dev_resume (dev); +schedule_work (&dev->probe_work); }static void nvme_shutdown (struct pci_dev *pdev)
@@ -3277,10 +3258,7 @@ static int nvme_resume(struct device *dev)struct pci_dev *pdev =to_pci_dev (dev);struct nvme_dev *ndev =pci_get_drvdata (pdev); -if (nvme_dev_resume (ndev) && !work_busy (&ndev->reset_work)) { - ndev->reset_workfn = nvme_reset_failed_dev; -queue_work (nvme_workq, &ndev->reset_work); - } +schedule_work (&ndev->probe_work); return 0; }#endif
include/linux/nvme.h +0 -1
@@ -104,7 +104,6 @@ struct nvme_dev {struct list_head namespaces;struct kref kref;struct device *device; -work_func_t reset_workfn;struct work_struct reset_work;struct work_struct probe_work;struct work_struct scan_work;
Signature · 1 line
1.7.10.4
PATCH v2 2/2 NVMe: Simplify device resume on io queue failure
Quoted 11 lines · Keith Busch
Releasing IO queues and disks was done in a work queue outside the controller resume context to delete namespaces if the controller failed after a resume from suspend. This is unnecessary since we can resume a device asynchronously.
This patch makes resume use
probe_workso it can directly remove namespaces if the device is manageable but not IO capable. Since the deleting disks was the only reason we had the convoluted "reset_workfn", this patch removes that unnecessary indirection.Signed-off-by Keith Busch <keith.busch at intel.com>
Looks good,
PATCH 1/2 NVMe: Namespace removal simplifications
In reply to Keith BuschLooks good,