mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 22:24:09 +08:00
nvme: fixes for NVME_IOCTL_IO_CMD on the char device
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>
This commit is contained in:
parent
69d3b8ac15
commit
bfd8947194
@ -922,21 +922,50 @@ static int nvme_dev_release(struct inode *inode, struct file *file)
|
|||||||
return 0;
|
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,
|
static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
struct nvme_ctrl *ctrl = file->private_data;
|
struct nvme_ctrl *ctrl = file->private_data;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
struct nvme_ns *ns;
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case NVME_IOCTL_ADMIN_CMD:
|
case NVME_IOCTL_ADMIN_CMD:
|
||||||
return nvme_user_cmd(ctrl, NULL, argp);
|
return nvme_user_cmd(ctrl, NULL, argp);
|
||||||
case NVME_IOCTL_IO_CMD:
|
case NVME_IOCTL_IO_CMD:
|
||||||
if (list_empty(&ctrl->namespaces))
|
return nvme_dev_user_cmd(ctrl, argp);
|
||||||
return -ENOTTY;
|
|
||||||
ns = list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
|
|
||||||
return nvme_user_cmd(ctrl, ns, argp);
|
|
||||||
case NVME_IOCTL_RESET:
|
case NVME_IOCTL_RESET:
|
||||||
dev_warn(ctrl->dev, "resetting controller\n");
|
dev_warn(ctrl->dev, "resetting controller\n");
|
||||||
return ctrl->ops->reset_ctrl(ctrl);
|
return ctrl->ops->reset_ctrl(ctrl);
|
||||||
|
Loading…
Reference in New Issue
Block a user