io_uring/kbuf: recycle freed mapped buffer ring entries
[linux-2.6-block.git] / io_uring / rw.c
index 63d343bae76229edf92a424a2691134ffc9a12be..64390d4e20c1875f92d944ad4fddd6c3ad8a140e 100644 (file)
@@ -83,18 +83,6 @@ int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        /* used for fixed read/write too - just read unconditionally */
        req->buf_index = READ_ONCE(sqe->buf_index);
 
-       if (req->opcode == IORING_OP_READ_FIXED ||
-           req->opcode == IORING_OP_WRITE_FIXED) {
-               struct io_ring_ctx *ctx = req->ctx;
-               u16 index;
-
-               if (unlikely(req->buf_index >= ctx->nr_user_bufs))
-                       return -EFAULT;
-               index = array_index_nospec(req->buf_index, ctx->nr_user_bufs);
-               req->imu = ctx->user_bufs[index];
-               io_req_set_rsrc_node(req, ctx, 0);
-       }
-
        ioprio = READ_ONCE(sqe->ioprio);
        if (ioprio) {
                ret = ioprio_check_cap(ioprio);
@@ -131,12 +119,31 @@ int io_prep_rwv(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        return 0;
 }
 
+int io_prep_rw_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       u16 index;
+       int ret;
+
+       ret = io_prep_rw(req, sqe);
+       if (unlikely(ret))
+               return ret;
+
+       if (unlikely(req->buf_index >= ctx->nr_user_bufs))
+               return -EFAULT;
+       index = array_index_nospec(req->buf_index, ctx->nr_user_bufs);
+       req->imu = ctx->user_bufs[index];
+       io_req_set_rsrc_node(req, ctx, 0);
+       return 0;
+}
+
 /*
  * Multishot read is prepared just like a normal read/write request, only
  * difference is that we set the MULTISHOT flag.
  */
 int io_read_mshot_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
+       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
        int ret;
 
        /* must be used with provided buffers */
@@ -147,6 +154,9 @@ int io_read_mshot_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (unlikely(ret))
                return ret;
 
+       if (rw->addr || rw->len)
+               return -EINVAL;
+
        req->flags |= REQ_F_APOLL_MULTISHOT;
        return 0;
 }
@@ -902,6 +912,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
 
 int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
 {
+       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
        unsigned int cflags = 0;
        int ret;
 
@@ -918,7 +929,12 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
         * handling arm it.
         */
        if (ret == -EAGAIN) {
-               io_kbuf_recycle(req, issue_flags);
+               /*
+                * Reset rw->len to 0 again to avoid clamping future mshot
+                * reads, in case the buffer size varies.
+                */
+               if (io_kbuf_recycle(req, issue_flags))
+                       rw->len = 0;
                return -EAGAIN;
        }
 
@@ -931,6 +947,7 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
                 * jump to the termination path. This request is then done.
                 */
                cflags = io_put_kbuf(req, issue_flags);
+               rw->len = 0; /* similarly to above, reset len to 0 */
 
                if (io_fill_cqe_req_aux(req,
                                        issue_flags & IO_URING_F_COMPLETE_DEFER,