]>
Commit | Line | Data |
---|---|---|
fb43722c SL |
1 | From c1e7f5043239b4a293a630b31a5f45bad1f37a4c 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 | |
5 | ioctls | |
6 | ||
7 | [ Upstream commit 5fb4aac756acacf260b9ebd88747251effa3a2f2 ] | |
8 | ||
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 | |
12 | ioctls to avoid that. | |
13 | ||
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> | |
19 | --- | |
20 | drivers/nvme/host/core.c | 25 ++++++++++++++++++++----- | |
21 | 1 file changed, 20 insertions(+), 5 deletions(-) | |
22 | ||
23 | diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c | |
24 | index 8b77e6a05f4b..23c90382a515 100644 | |
25 | --- a/drivers/nvme/host/core.c | |
26 | +++ b/drivers/nvme/host/core.c | |
27 | @@ -1395,14 +1395,31 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, | |
28 | if (unlikely(!ns)) | |
29 | return -EWOULDBLOCK; | |
30 | ||
31 | + /* | |
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. | |
35 | + */ | |
36 | + if (cmd == NVME_IOCTL_ADMIN_CMD || is_sed_ioctl(cmd)) { | |
37 | + struct nvme_ctrl *ctrl = ns->ctrl; | |
38 | + | |
39 | + nvme_get_ctrl(ns->ctrl); | |
40 | + nvme_put_ns_from_disk(head, srcu_idx); | |
41 | + | |
42 | + if (cmd == NVME_IOCTL_ADMIN_CMD) | |
43 | + ret = nvme_user_cmd(ctrl, NULL, argp); | |
44 | + else | |
45 | + ret = sed_ioctl(ctrl->opal_dev, cmd, argp); | |
46 | + | |
47 | + nvme_put_ctrl(ctrl); | |
48 | + return ret; | |
49 | + } | |
50 | + | |
51 | switch (cmd) { | |
52 | case NVME_IOCTL_ID: | |
53 | force_successful_syscall_return(); | |
54 | ret = ns->head->ns_id; | |
55 | break; | |
56 | - case NVME_IOCTL_ADMIN_CMD: | |
57 | - ret = nvme_user_cmd(ns->ctrl, NULL, argp); | |
58 | - break; | |
59 | case NVME_IOCTL_IO_CMD: | |
60 | ret = nvme_user_cmd(ns->ctrl, ns, argp); | |
61 | break; | |
62 | @@ -1412,8 +1429,6 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, | |
63 | default: | |
64 | if (ns->ndev) | |
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); | |
68 | else | |
69 | ret = -ENOTTY; | |
70 | } | |
71 | -- | |
72 | 2.20.1 | |
73 |