nvme: add vectored-io support for user-passthrough
Add a new NVME_IOCTL_IO64_CMD_VEC ioctl that works like the existing NVME_IOCTL_IO64_CMD ioctl except that it takes and array of iovecs and thus supports vectored I/O. - cmd.addr is base address of user iovec array - cmd.vec_cnt is count of iovec array elements This patch does not include vectored-variant for admin-commands as most of them are light on buffers and likely to have low invocation frequency. Signed-off-by: Kanchan Joshi <joshi.k@samsung.com> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Родитель
bd83fe6f2c
Коммит
89377bc197
|
@ -56,7 +56,7 @@ out:
|
|||
static int nvme_submit_user_cmd(struct request_queue *q,
|
||||
struct nvme_command *cmd, void __user *ubuffer,
|
||||
unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
|
||||
u32 meta_seed, u64 *result, unsigned timeout)
|
||||
u32 meta_seed, u64 *result, unsigned timeout, bool vec)
|
||||
{
|
||||
bool write = nvme_is_write(cmd);
|
||||
struct nvme_ns *ns = q->queuedata;
|
||||
|
@ -75,8 +75,22 @@ static int nvme_submit_user_cmd(struct request_queue *q,
|
|||
nvme_req(req)->flags |= NVME_REQ_USERCMD;
|
||||
|
||||
if (ubuffer && bufflen) {
|
||||
ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
|
||||
if (!vec)
|
||||
ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
|
||||
GFP_KERNEL);
|
||||
else {
|
||||
struct iovec fast_iov[UIO_FASTIOV];
|
||||
struct iovec *iov = fast_iov;
|
||||
struct iov_iter iter;
|
||||
|
||||
ret = import_iovec(rq_data_dir(req), ubuffer, bufflen,
|
||||
UIO_FASTIOV, &iov, &iter);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = blk_rq_map_user_iov(q, req, NULL, &iter,
|
||||
GFP_KERNEL);
|
||||
kfree(iov);
|
||||
}
|
||||
if (ret)
|
||||
goto out;
|
||||
bio = req->bio;
|
||||
|
@ -170,7 +184,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
|
|||
|
||||
return nvme_submit_user_cmd(ns->queue, &c,
|
||||
nvme_to_user_ptr(io.addr), length,
|
||||
metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
|
||||
metadata, meta_len, lower_32_bits(io.slba), NULL, 0,
|
||||
false);
|
||||
}
|
||||
|
||||
static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl,
|
||||
|
@ -224,7 +239,7 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
|
|||
status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
|
||||
nvme_to_user_ptr(cmd.addr), cmd.data_len,
|
||||
nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
|
||||
0, &result, timeout);
|
||||
0, &result, timeout, false);
|
||||
|
||||
if (status >= 0) {
|
||||
if (put_user(result, &ucmd->result))
|
||||
|
@ -235,7 +250,7 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
|
|||
}
|
||||
|
||||
static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
|
||||
struct nvme_passthru_cmd64 __user *ucmd)
|
||||
struct nvme_passthru_cmd64 __user *ucmd, bool vec)
|
||||
{
|
||||
struct nvme_passthru_cmd64 cmd;
|
||||
struct nvme_command c;
|
||||
|
@ -270,7 +285,7 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
|
|||
status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
|
||||
nvme_to_user_ptr(cmd.addr), cmd.data_len,
|
||||
nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
|
||||
0, &cmd.result, timeout);
|
||||
0, &cmd.result, timeout, vec);
|
||||
|
||||
if (status >= 0) {
|
||||
if (put_user(cmd.result, &ucmd->result))
|
||||
|
@ -296,7 +311,7 @@ static int nvme_ctrl_ioctl(struct nvme_ctrl *ctrl, unsigned int cmd,
|
|||
case NVME_IOCTL_ADMIN_CMD:
|
||||
return nvme_user_cmd(ctrl, NULL, argp);
|
||||
case NVME_IOCTL_ADMIN64_CMD:
|
||||
return nvme_user_cmd64(ctrl, NULL, argp);
|
||||
return nvme_user_cmd64(ctrl, NULL, argp, false);
|
||||
default:
|
||||
return sed_ioctl(ctrl->opal_dev, cmd, argp);
|
||||
}
|
||||
|
@ -340,7 +355,9 @@ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,
|
|||
case NVME_IOCTL_SUBMIT_IO:
|
||||
return nvme_submit_io(ns, argp);
|
||||
case NVME_IOCTL_IO64_CMD:
|
||||
return nvme_user_cmd64(ns->ctrl, ns, argp);
|
||||
return nvme_user_cmd64(ns->ctrl, ns, argp, false);
|
||||
case NVME_IOCTL_IO64_CMD_VEC:
|
||||
return nvme_user_cmd64(ns->ctrl, ns, argp, true);
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
@ -480,7 +497,7 @@ long nvme_dev_ioctl(struct file *file, unsigned int cmd,
|
|||
case NVME_IOCTL_ADMIN_CMD:
|
||||
return nvme_user_cmd(ctrl, NULL, argp);
|
||||
case NVME_IOCTL_ADMIN64_CMD:
|
||||
return nvme_user_cmd64(ctrl, NULL, argp);
|
||||
return nvme_user_cmd64(ctrl, NULL, argp, false);
|
||||
case NVME_IOCTL_IO_CMD:
|
||||
return nvme_dev_user_cmd(ctrl, argp);
|
||||
case NVME_IOCTL_RESET:
|
||||
|
|
|
@ -55,7 +55,10 @@ struct nvme_passthru_cmd64 {
|
|||
__u64 metadata;
|
||||
__u64 addr;
|
||||
__u32 metadata_len;
|
||||
__u32 data_len;
|
||||
union {
|
||||
__u32 data_len; /* for non-vectored io */
|
||||
__u32 vec_cnt; /* for vectored io */
|
||||
};
|
||||
__u32 cdw10;
|
||||
__u32 cdw11;
|
||||
__u32 cdw12;
|
||||
|
@ -78,5 +81,6 @@ struct nvme_passthru_cmd64 {
|
|||
#define NVME_IOCTL_RESCAN _IO('N', 0x46)
|
||||
#define NVME_IOCTL_ADMIN64_CMD _IOWR('N', 0x47, struct nvme_passthru_cmd64)
|
||||
#define NVME_IOCTL_IO64_CMD _IOWR('N', 0x48, struct nvme_passthru_cmd64)
|
||||
#define NVME_IOCTL_IO64_CMD_VEC _IOWR('N', 0x49, struct nvme_passthru_cmd64)
|
||||
|
||||
#endif /* _UAPI_LINUX_NVME_IOCTL_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче