Merge tag 'riscv-for-linus-5.20-mw0' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / block / ublk_drv.c
index 20ad83b..2b7d1db 100644 (file)
@@ -47,7 +47,9 @@
 #define UBLK_MINORS            (1U << MINORBITS)
 
 /* All UBLK_F_* have to be included into UBLK_F_ALL */
-#define UBLK_F_ALL (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_URING_CMD_COMP_IN_TASK)
+#define UBLK_F_ALL (UBLK_F_SUPPORT_ZERO_COPY \
+               | UBLK_F_URING_CMD_COMP_IN_TASK \
+               | UBLK_F_NEED_GET_DATA)
 
 /* All UBLK_PARAM_TYPE_* should be included here */
 #define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD)
@@ -89,6 +91,15 @@ struct ublk_uring_cmd_pdu {
  */
 #define UBLK_IO_FLAG_ABORTED 0x04
 
+/*
+ * UBLK_IO_FLAG_NEED_GET_DATA is set because IO command requires
+ * get data buffer address from ublksrv.
+ *
+ * Then, bio data could be copied into this data buffer for a WRITE request
+ * after the IO command is issued again and UBLK_IO_FLAG_NEED_GET_DATA is unset.
+ */
+#define UBLK_IO_FLAG_NEED_GET_DATA 0x08
+
 struct ublk_io {
        /* userspace buffer address from io cmd */
        __u64   addr;
@@ -122,7 +133,6 @@ struct ublk_device {
        char    *__queues;
 
        unsigned short  queue_size;
-       unsigned short  bs_shift;
        struct ublksrv_ctrl_dev_info    dev_info;
 
        struct blk_mq_tag_set   tag_set;
@@ -223,8 +233,7 @@ static int ublk_validate_params(const struct ublk_device *ub)
                if (p->logical_bs_shift > p->physical_bs_shift)
                        return -EINVAL;
 
-               if (p->max_sectors > (ub->dev_info.rq_max_blocks <<
-                                       (ub->bs_shift - 9)))
+               if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9))
                        return -EINVAL;
        } else
                return -EINVAL;
@@ -264,6 +273,13 @@ static inline bool ublk_can_use_task_work(const struct ublk_queue *ubq)
        return false;
 }
 
+static inline bool ublk_need_get_data(const struct ublk_queue *ubq)
+{
+       if (ubq->flags & UBLK_F_NEED_GET_DATA)
+               return true;
+       return false;
+}
+
 static struct ublk_device *ublk_get_device(struct ublk_device *ub)
 {
        if (kobject_get_unless_zero(&ub->cdev_dev.kobj))
@@ -605,6 +621,21 @@ static void __ublk_fail_req(struct ublk_io *io, struct request *req)
        }
 }
 
+static void ubq_complete_io_cmd(struct ublk_io *io, int res)
+{
+       /* mark this cmd owned by ublksrv */
+       io->flags |= UBLK_IO_FLAG_OWNED_BY_SRV;
+
+       /*
+        * clear ACTIVE since we are done with this sqe/cmd slot
+        * We can only accept io cmd in case of being not active.
+        */
+       io->flags &= ~UBLK_IO_FLAG_ACTIVE;
+
+       /* tell ublksrv one io request is coming */
+       io_uring_cmd_done(io->cmd, res, 0);
+}
+
 #define UBLK_REQUEUE_DELAY_MS  3
 
 static inline void __ublk_rq_task_work(struct request *req)
@@ -627,6 +658,30 @@ static inline void __ublk_rq_task_work(struct request *req)
                return;
        }
 
+       if (ublk_need_get_data(ubq) &&
+                       (req_op(req) == REQ_OP_WRITE ||
+                       req_op(req) == REQ_OP_FLUSH)) {
+               /*
+                * We have not handled UBLK_IO_NEED_GET_DATA command yet,
+                * so immepdately pass UBLK_IO_RES_NEED_GET_DATA to ublksrv
+                * and notify it.
+                */
+               if (!(io->flags & UBLK_IO_FLAG_NEED_GET_DATA)) {
+                       io->flags |= UBLK_IO_FLAG_NEED_GET_DATA;
+                       pr_devel("%s: need get data. op %d, qid %d tag %d io_flags %x\n",
+                                       __func__, io->cmd->cmd_op, ubq->q_id,
+                                       req->tag, io->flags);
+                       ubq_complete_io_cmd(io, UBLK_IO_RES_NEED_GET_DATA);
+                       return;
+               }
+               /*
+                * We have handled UBLK_IO_NEED_GET_DATA command,
+                * so clear UBLK_IO_FLAG_NEED_GET_DATA now and just
+                * do the copy work.
+                */
+               io->flags &= ~UBLK_IO_FLAG_NEED_GET_DATA;
+       }
+
        mapped_bytes = ublk_map_io(ubq, req, io);
 
        /* partially mapped, update io descriptor */
@@ -649,17 +704,7 @@ static inline void __ublk_rq_task_work(struct request *req)
                        mapped_bytes >> 9;
        }
 
-       /* mark this cmd owned by ublksrv */
-       io->flags |= UBLK_IO_FLAG_OWNED_BY_SRV;
-
-       /*
-        * clear ACTIVE since we are done with this sqe/cmd slot
-        * We can only accept io cmd in case of being not active.
-        */
-       io->flags &= ~UBLK_IO_FLAG_ACTIVE;
-
-       /* tell ublksrv one io request is coming */
-       io_uring_cmd_done(io->cmd, UBLK_IO_RES_OK, 0);
+       ubq_complete_io_cmd(io, UBLK_IO_RES_OK);
 }
 
 static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd)
@@ -948,6 +993,25 @@ static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq)
        mutex_unlock(&ub->mutex);
 }
 
+static void ublk_handle_need_get_data(struct ublk_device *ub, int q_id,
+               int tag, struct io_uring_cmd *cmd)
+{
+       struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
+       struct request *req = blk_mq_tag_to_rq(ub->tag_set.tags[q_id], tag);
+
+       if (ublk_can_use_task_work(ubq)) {
+               struct ublk_rq_data *data = blk_mq_rq_to_pdu(req);
+
+               /* should not fail since we call it just in ubq->ubq_daemon */
+               task_work_add(ubq->ubq_daemon, &data->work, TWA_SIGNAL_NO_IPI);
+       } else {
+               struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
+
+               pdu->req = req;
+               io_uring_cmd_complete_in_task(cmd, ublk_rq_task_work_cb);
+       }
+}
+
 static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 {
        struct ublksrv_io_cmd *ub_cmd = (struct ublksrv_io_cmd *)cmd->cmd;
@@ -986,6 +1050,14 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
                goto out;
        }
 
+       /*
+        * ensure that the user issues UBLK_IO_NEED_GET_DATA
+        * iff the driver have set the UBLK_IO_FLAG_NEED_GET_DATA.
+        */
+       if ((!!(io->flags & UBLK_IO_FLAG_NEED_GET_DATA))
+                       ^ (cmd_op == UBLK_IO_NEED_GET_DATA))
+               goto out;
+
        switch (cmd_op) {
        case UBLK_IO_FETCH_REQ:
                /* UBLK_IO_FETCH_REQ is only allowed before queue is setup */
@@ -1019,6 +1091,14 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
                io->cmd = cmd;
                ublk_commit_completion(ub, ub_cmd);
                break;
+       case UBLK_IO_NEED_GET_DATA:
+               if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
+                       goto out;
+               io->addr = ub_cmd->addr;
+               io->cmd = cmd;
+               io->flags |= UBLK_IO_FLAG_ACTIVE;
+               ublk_handle_need_get_data(ub, ub_cmd->q_id, ub_cmd->tag, cmd);
+               break;
        default:
                goto out;
        }
@@ -1185,13 +1265,13 @@ static void ublk_stop_work_fn(struct work_struct *work)
        ublk_stop_dev(ub);
 }
 
-/* align maximum I/O size to PAGE_SIZE */
+/* align max io buffer size with PAGE_SIZE */
 static void ublk_align_max_io_size(struct ublk_device *ub)
 {
-       unsigned int max_rq_bytes = ub->dev_info.rq_max_blocks << ub->bs_shift;
+       unsigned int max_io_bytes = ub->dev_info.max_io_buf_bytes;
 
-       ub->dev_info.rq_max_blocks =
-               round_down(max_rq_bytes, PAGE_SIZE) >> ub->bs_shift;
+       ub->dev_info.max_io_buf_bytes =
+               round_down(max_io_bytes, PAGE_SIZE);
 }
 
 static int ublk_add_tag_set(struct ublk_device *ub)
@@ -1348,9 +1428,8 @@ static inline void ublk_dump_dev_info(struct ublksrv_ctrl_dev_info *info)
 {
        pr_devel("%s: dev id %d flags %llx\n", __func__,
                        info->dev_id, info->flags);
-       pr_devel("\t nr_hw_queues %d queue_depth %d block size %d dev_capacity %lld\n",
-                       info->nr_hw_queues, info->queue_depth,
-                       info->block_size, info->dev_blocks);
+       pr_devel("\t nr_hw_queues %d queue_depth %d\n",
+                       info->nr_hw_queues, info->queue_depth);
 }
 
 static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
@@ -1410,7 +1489,6 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
        /* We are not ready to support zero copy */
        ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;
 
-       ub->bs_shift = ilog2(ub->dev_info.block_size);
        ub->dev_info.nr_hw_queues = min_t(unsigned int,
                        ub->dev_info.nr_hw_queues, nr_cpu_ids);
        ublk_align_max_io_size(ub);