diff options
author | Sunad Bhandary <sunad.s@samsung.com> | 2016-05-27 13:29:43 +0300 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-06-08 17:48:47 +0300 |
commit | 47b0e50ac724d97c392f771bb46f11d9d1575242 (patch) | |
tree | d7b8a1a5029d1429760e8f90eda1a619a97c18c0 /drivers/nvme | |
parent | bd0fc2884ca4d1516da1aa5cf44385e24dc23c29 (diff) | |
download | linux-47b0e50ac724d97c392f771bb46f11d9d1575242.tar.xz |
NVMe: Fix removal in case of active namespace list scanning method
In case of the active namespace list scanning method, a namespace that
is detached is not removed from the host if it was the last entry in
the list. Fix this by adding a scan to validate namespaces greater than
the value of prev.
This also handles the case of removing namespaces whose value exceed
the device's reported number of namespaces.
Signed-off-by: Sunad Bhandary S <sunad.s@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/nvme')
-rw-r--r-- | drivers/nvme/host/core.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 99a95bad3ce4..684062a9d392 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1528,6 +1528,17 @@ static void nvme_validate_ns(struct nvme_ctrl *ctrl, unsigned nsid) nvme_alloc_ns(ctrl, nsid); } +static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl, + unsigned nsid) +{ + struct nvme_ns *ns, *next; + + list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) { + if (ns->ns_id > nsid) + nvme_ns_remove(ns); + } +} + static int nvme_scan_ns_list(struct nvme_ctrl *ctrl, unsigned nn) { struct nvme_ns *ns; @@ -1542,7 +1553,7 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl, unsigned nn) for (i = 0; i < num_lists; i++) { ret = nvme_identify_ns_list(ctrl, prev, ns_list); if (ret) - goto out; + goto free; for (j = 0; j < min(nn, 1024U); j++) { nsid = le32_to_cpu(ns_list[j]); @@ -1560,13 +1571,14 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl, unsigned nn) nn -= j; } out: + nvme_remove_invalid_namespaces(ctrl, prev); + free: kfree(ns_list); return ret; } static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl, unsigned nn) { - struct nvme_ns *ns, *next; unsigned i; lockdep_assert_held(&ctrl->namespaces_mutex); @@ -1574,10 +1586,7 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl, unsigned nn) for (i = 1; i <= nn; i++) nvme_validate_ns(ctrl, i); - list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) { - if (ns->ns_id > nn) - nvme_ns_remove(ns); - } + nvme_remove_invalid_namespaces(ctrl, nn); } static void nvme_scan_work(struct work_struct *work) |