aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSagi Grimberg <sagi@grimberg.me>2017-12-21 08:07:27 -0500
committerChristoph Hellwig <hch@lst.de>2017-12-29 04:32:58 -0500
commit479a322fb729d657d34706ccf8dd12916f36628f (patch)
treed048b15739f2cffd4ab5487c0fb348378692793d
parentd5bf4b7f437c250821d40c3e32158729e6b484ce (diff)
nvme-mpath: fix last path removal during traffic
In case our last path is removed during traffic, we can end up requeueing the bio(s) but never schedule the actual requeue work as upper layers still have open handles on the mpath device node. Fix this by scheduling requeue work if the namespace being removed is the last path in the ns_head path list. Fixes: 32acab3181c7 ("nvme: implement multipath access to nvme subsystems") Signed-off-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/nvme/host/core.c1
-rw-r--r--drivers/nvme/host/nvme.h12
2 files changed, 13 insertions, 0 deletions
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 961d6a4af19c..839650e0926a 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2991,6 +2991,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
2991 mutex_unlock(&ns->ctrl->namespaces_mutex); 2991 mutex_unlock(&ns->ctrl->namespaces_mutex);
2992 2992
2993 synchronize_srcu(&ns->head->srcu); 2993 synchronize_srcu(&ns->head->srcu);
2994 nvme_mpath_check_last_path(ns);
2994 nvme_put_ns(ns); 2995 nvme_put_ns(ns);
2995} 2996}
2996 2997
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ea1aa5283e8e..a00eabd06427 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -417,6 +417,15 @@ static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
417 rcu_assign_pointer(head->current_path, NULL); 417 rcu_assign_pointer(head->current_path, NULL);
418} 418}
419struct nvme_ns *nvme_find_path(struct nvme_ns_head *head); 419struct nvme_ns *nvme_find_path(struct nvme_ns_head *head);
420
421static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
422{
423 struct nvme_ns_head *head = ns->head;
424
425 if (head->disk && list_empty(&head->list))
426 kblockd_schedule_work(&head->requeue_work);
427}
428
420#else 429#else
421static inline void nvme_failover_req(struct request *req) 430static inline void nvme_failover_req(struct request *req)
422{ 431{
@@ -448,6 +457,9 @@ static inline void nvme_mpath_remove_disk_links(struct nvme_ns *ns)
448static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) 457static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
449{ 458{
450} 459}
460static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
461{
462}
451#endif /* CONFIG_NVME_MULTIPATH */ 463#endif /* CONFIG_NVME_MULTIPATH */
452 464
453#ifdef CONFIG_NVM 465#ifdef CONFIG_NVM