aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/nvme/host/core.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index bc288990fd50..d4226c18eb71 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1394,14 +1394,31 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
1394 if (unlikely(!ns)) 1394 if (unlikely(!ns))
1395 return -EWOULDBLOCK; 1395 return -EWOULDBLOCK;
1396 1396
1397 /*
1398 * Handle ioctls that apply to the controller instead of the namespace
1399 * seperately and drop the ns SRCU reference early. This avoids a
1400 * deadlock when deleting namespaces using the passthrough interface.
1401 */
1402 if (cmd == NVME_IOCTL_ADMIN_CMD || is_sed_ioctl(cmd)) {
1403 struct nvme_ctrl *ctrl = ns->ctrl;
1404
1405 nvme_get_ctrl(ns->ctrl);
1406 nvme_put_ns_from_disk(head, srcu_idx);
1407
1408 if (cmd == NVME_IOCTL_ADMIN_CMD)
1409 ret = nvme_user_cmd(ctrl, NULL, argp);
1410 else
1411 ret = sed_ioctl(ctrl->opal_dev, cmd, argp);
1412
1413 nvme_put_ctrl(ctrl);
1414 return ret;
1415 }
1416
1397 switch (cmd) { 1417 switch (cmd) {
1398 case NVME_IOCTL_ID: 1418 case NVME_IOCTL_ID:
1399 force_successful_syscall_return(); 1419 force_successful_syscall_return();
1400 ret = ns->head->ns_id; 1420 ret = ns->head->ns_id;
1401 break; 1421 break;
1402 case NVME_IOCTL_ADMIN_CMD:
1403 ret = nvme_user_cmd(ns->ctrl, NULL, argp);
1404 break;
1405 case NVME_IOCTL_IO_CMD: 1422 case NVME_IOCTL_IO_CMD:
1406 ret = nvme_user_cmd(ns->ctrl, ns, argp); 1423 ret = nvme_user_cmd(ns->ctrl, ns, argp);
1407 break; 1424 break;
@@ -1411,8 +1428,6 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
1411 default: 1428 default:
1412 if (ns->ndev) 1429 if (ns->ndev)
1413 ret = nvme_nvm_ioctl(ns, cmd, arg); 1430 ret = nvme_nvm_ioctl(ns, cmd, arg);
1414 else if (is_sed_ioctl(cmd))
1415 ret = sed_ioctl(ns->ctrl->opal_dev, cmd, argp);
1416 else 1431 else
1417 ret = -ENOTTY; 1432 ret = -ENOTTY;
1418 } 1433 }