1 From db251685664dd1cf36456732d5372b31b0f69d12 Mon Sep 17 00:00:00 2001
2 From: Christoph Hellwig <hch@lst.de>
3 Date: Fri, 17 May 2019 11:47:36 +0200
4 Subject: nvme: release namespace SRCU protection before performing controller
7 [ Upstream commit 5fb4aac756acacf260b9ebd88747251effa3a2f2 ]
9 Holding the SRCU critical section protecting the namespace list can
10 cause deadlocks when using the per-namespace admin passthrough ioctl to
11 delete as namespace. Release it earlier when performing per-controller
14 Reported-by: Kenneth Heitke <kenneth.heitke@intel.com>
15 Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
16 Reviewed-by: Keith Busch <keith.busch@intel.com>
17 Signed-off-by: Christoph Hellwig <hch@lst.de>
18 Signed-off-by: Sasha Levin <sashal@kernel.org>
20 drivers/nvme/host/core.c | 25 ++++++++++++++++++++-----
21 1 file changed, 20 insertions(+), 5 deletions(-)
23 diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
24 index 82f5f1d030d4..818788275406 100644
25 --- a/drivers/nvme/host/core.c
26 +++ b/drivers/nvme/host/core.c
27 @@ -1310,14 +1310,31 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
32 + * Handle ioctls that apply to the controller instead of the namespace
33 + * seperately and drop the ns SRCU reference early. This avoids a
34 + * deadlock when deleting namespaces using the passthrough interface.
36 + if (cmd == NVME_IOCTL_ADMIN_CMD || is_sed_ioctl(cmd)) {
37 + struct nvme_ctrl *ctrl = ns->ctrl;
39 + nvme_get_ctrl(ns->ctrl);
40 + nvme_put_ns_from_disk(head, srcu_idx);
42 + if (cmd == NVME_IOCTL_ADMIN_CMD)
43 + ret = nvme_user_cmd(ctrl, NULL, argp);
45 + ret = sed_ioctl(ctrl->opal_dev, cmd, argp);
47 + nvme_put_ctrl(ctrl);
53 force_successful_syscall_return();
54 ret = ns->head->ns_id;
56 - case NVME_IOCTL_ADMIN_CMD:
57 - ret = nvme_user_cmd(ns->ctrl, NULL, argp);
59 case NVME_IOCTL_IO_CMD:
60 ret = nvme_user_cmd(ns->ctrl, ns, argp);
62 @@ -1327,8 +1344,6 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
65 ret = nvme_nvm_ioctl(ns, cmd, arg);
66 - else if (is_sed_ioctl(cmd))
67 - ret = sed_ioctl(ns->ctrl->opal_dev, cmd, argp);