@@ -653,6 +653,23 @@ static bool is_ctrl_ioctl(unsigned int cmd)
return false;
}
+static int nvme_uring_cmd_io_direct(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+ struct io_uring_cmd *ioucmd, unsigned int issue_flags)
+{
+ struct request_queue *q = ns ? ns->queue : ctrl->admin_q;
+ int qid = io_uring_cmd_import_qid(ioucmd);
+ struct nvme_uring_direct_pdu *pdu =
+ (struct nvme_uring_direct_pdu *)&ioucmd->pdu;
+
+ if ((issue_flags & IO_URING_F_IOPOLL) != IO_URING_F_IOPOLL)
+ return -EOPNOTSUPP;
+
+ pdu->ns = ns;
+ if (q->mq_ops && q->mq_ops->queue_uring_cmd)
+ return q->mq_ops->queue_uring_cmd(ioucmd, qid);
+ return -EOPNOTSUPP;
+}
+
static int nvme_ctrl_ioctl(struct nvme_ctrl *ctrl, unsigned int cmd,
void __user *argp, fmode_t mode)
{
@@ -763,6 +780,14 @@ static int nvme_ns_uring_cmd(struct nvme_ns *ns, struct io_uring_cmd *ioucmd,
switch (ioucmd->cmd_op) {
case NVME_URING_CMD_IO:
+ if (ioucmd->flags & IORING_URING_CMD_DIRECT) {
+ ret = nvme_uring_cmd_io_direct(ctrl, ns, ioucmd,
+ issue_flags);
+ if (ret == -EIOCBQUEUED)
+ return ret;
+ /* in case of any error, just fallback */
+ ioucmd->flags &= ~(IORING_URING_CMD_DIRECT);
+ }
ret = nvme_uring_cmd_io(ctrl, ns, ioucmd, issue_flags, false);
break;
case NVME_URING_CMD_IO_VEC:
@@ -783,6 +808,38 @@ int nvme_ns_chr_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags)
return nvme_ns_uring_cmd(ns, ioucmd, issue_flags);
}
+/* similar to blk_mq_poll; may be possible to unify */
+int nvme_uring_cmd_iopoll_qid(struct request_queue *q,
+ struct io_uring_cmd *ioucmd, int qid,
+ struct io_comp_batch *iob,
+ unsigned int flags)
+{
+ long state = get_current_state();
+ int ret;
+
+ if (!(q->mq_ops && q->mq_ops->poll_uring_cmd))
+ return 0;
+ do {
+ ret = q->mq_ops->poll_uring_cmd(ioucmd, qid, iob);
+ if (ret > 0) {
+ __set_current_state(TASK_RUNNING);
+ return ret;
+ }
+ if (signal_pending_state(state, current))
+ __set_current_state(TASK_RUNNING);
+ if (task_is_running(current))
+ return 1;
+
+ if (ret < 0 || (flags & BLK_POLL_ONESHOT))
+ break;
+ cpu_relax();
+
+ } while (!need_resched());
+
+ __set_current_state(TASK_RUNNING);
+ return 0;
+}
+
int nvme_ns_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd,
struct io_comp_batch *iob,
unsigned int poll_flags)
@@ -792,14 +849,26 @@ int nvme_ns_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd,
struct nvme_ns *ns;
struct request_queue *q;
- rcu_read_lock();
- bio = READ_ONCE(ioucmd->cookie);
ns = container_of(file_inode(ioucmd->file)->i_cdev,
struct nvme_ns, cdev);
q = ns->queue;
- if (test_bit(QUEUE_FLAG_POLL, &q->queue_flags) && bio && bio->bi_bdev)
- ret = bio_poll(bio, iob, poll_flags);
- rcu_read_unlock();
+ if (!(ioucmd->flags & IORING_URING_CMD_DIRECT)) {
+ rcu_read_lock();
+ bio = READ_ONCE(ioucmd->cookie);
+ if (test_bit(QUEUE_FLAG_POLL, &q->queue_flags) && bio && bio->bi_bdev)
+ ret = bio_poll(bio, iob, poll_flags);
+
+ rcu_read_unlock();
+ } else {
+ int qid = io_uring_cmd_import_qid(ioucmd);
+
+ if (qid <= 0)
+ return 0;
+ if (!percpu_ref_tryget(&q->q_usage_counter))
+ return 0;
+ ret = nvme_uring_cmd_iopoll_qid(q, ioucmd, qid, iob, poll_flags);
+ percpu_ref_put(&q->q_usage_counter);
+ }
return ret;
}
#ifdef CONFIG_NVME_MULTIPATH
@@ -952,13 +1021,25 @@ int nvme_ns_head_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd,
struct request_queue *q;
if (ns) {
- rcu_read_lock();
- bio = READ_ONCE(ioucmd->cookie);
- q = ns->queue;
- if (test_bit(QUEUE_FLAG_POLL, &q->queue_flags) && bio
- && bio->bi_bdev)
- ret = bio_poll(bio, iob, poll_flags);
- rcu_read_unlock();
+ if (!(ioucmd->flags & IORING_URING_CMD_DIRECT)) {
+ rcu_read_lock();
+ bio = READ_ONCE(ioucmd->cookie);
+ q = ns->queue;
+ if (test_bit(QUEUE_FLAG_POLL, &q->queue_flags) && bio
+ && bio->bi_bdev)
+ ret = bio_poll(bio, iob, poll_flags);
+ rcu_read_unlock();
+ } else {
+ int qid = io_uring_cmd_import_qid(ioucmd);
+
+ if (qid <= 0)
+ return 0;
+ if (!percpu_ref_tryget(&q->q_usage_counter))
+ return 0;
+ ret = nvme_uring_cmd_iopoll_qid(q, ioucmd, qid, iob,
+ poll_flags);
+ percpu_ref_put(&q->q_usage_counter);
+ }
}
srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
@@ -176,6 +176,10 @@ struct nvme_uring_data {
__u32 timeout_ms;
};
+struct nvme_uring_direct_pdu {
+ struct nvme_ns *ns;
+};
+
/*
* Mark a bio as coming in through the mpath node.
*/
If IORING_URING_CMD_DIRECT flag is set, get the registered qid and - submit the io_uring command via mq_ops->queue_uring_cmd. - complete it via mq_ops->poll_uring_cmd. If the command could not be submitted this way due to any reason, abstract it and fallback to old way of submission. This keeps IORING_URING_CMD_DIRECT flag advisory. Signed-off-by: Kanchan Joshi <joshi.k@samsung.com> --- drivers/nvme/host/ioctl.c | 105 +++++++++++++++++++++++++++++++++----- drivers/nvme/host/nvme.h | 4 ++ 2 files changed, 97 insertions(+), 12 deletions(-)