Skip to content

Commit

Permalink
nvme: fixes for NVME_IOCTL_IO_CMD on the char device
Browse files Browse the repository at this point in the history
Make sure we synchronize access to the namespaces list and grab a reference
to the namespace before doing I/O.  Make sure to reject the ioctl if multiple
namespaces are present as it's entirely unsafe, and warn when using it even
with a single namespace.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Acked-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
  • Loading branch information
Christoph Hellwig authored and Jens Axboe committed Jan 12, 2016
1 parent 69d3b8a commit bfd8947
Showing 1 changed file with 34 additions and 5 deletions.
39 changes: 34 additions & 5 deletions drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -922,21 +922,50 @@ static int nvme_dev_release(struct inode *inode, struct file *file)
return 0;
}

static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp)
{
struct nvme_ns *ns;
int ret;

mutex_lock(&ctrl->namespaces_mutex);
if (list_empty(&ctrl->namespaces)) {
ret = -ENOTTY;
goto out_unlock;
}

ns = list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
if (ns != list_last_entry(&ctrl->namespaces, struct nvme_ns, list)) {
dev_warn(ctrl->dev,
"NVME_IOCTL_IO_CMD not supported when multiple namespaces present!\n");
ret = -EINVAL;
goto out_unlock;
}

dev_warn(ctrl->dev,
"using deprecated NVME_IOCTL_IO_CMD ioctl on the char device!\n");
kref_get(&ns->kref);
mutex_unlock(&ctrl->namespaces_mutex);

ret = nvme_user_cmd(ctrl, ns, argp);
nvme_put_ns(ns);
return ret;

out_unlock:
mutex_unlock(&ctrl->namespaces_mutex);
return ret;
}

static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct nvme_ctrl *ctrl = file->private_data;
void __user *argp = (void __user *)arg;
struct nvme_ns *ns;

switch (cmd) {
case NVME_IOCTL_ADMIN_CMD:
return nvme_user_cmd(ctrl, NULL, argp);
case NVME_IOCTL_IO_CMD:
if (list_empty(&ctrl->namespaces))
return -ENOTTY;
ns = list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
return nvme_user_cmd(ctrl, ns, argp);
return nvme_dev_user_cmd(ctrl, argp);
case NVME_IOCTL_RESET:
dev_warn(ctrl->dev, "resetting controller\n");
return ctrl->ops->reset_ctrl(ctrl);
Expand Down

0 comments on commit bfd8947

Please sign in to comment.