Commit 89377bc1 authored by Kanchan Joshi's avatar Kanchan Joshi Committed by Christoph Hellwig
Browse files

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: default avatarKanchan Joshi <joshi.k@samsung.com>
Reviewed-by: default avatarSagi Grimberg <sagi@grimberg.me>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent bd83fe6f
Loading
Loading
Loading
Loading
+26 −9
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ static void *nvme_add_user_metadata(struct bio *bio, void __user *ubuf,
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) {
		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:
+5 −1
Original line number Diff line number Diff line
@@ -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 */