From: Jens Axboe <axboe@kernel.dk>
To: io-uring@vger.kernel.org
Cc: david@fromorbit.com, jmoyer@redhat.com, Jens Axboe <axboe@kernel.dk>
Subject: [PATCH 1/2] io_uring: retain iov_iter state over io_read/io_write calls
Date: Fri, 14 Aug 2020 12:54:48 -0700 [thread overview]
Message-ID: <20200814195449.533153-2-axboe@kernel.dk> (raw)
In-Reply-To: <20200814195449.533153-1-axboe@kernel.dk>
Instead of maintaining (and setting/remembering) iov_iter size and
segment counts, just put the iov_iter in the async part of the IO
structure.
This is mostly a preparation patch for doing appropriate internal retries
for short reads, but it also cleans up the state handling nicely and
simplifies it quite a bit.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
fs/io_uring.c | 114 ++++++++++++++++++++++++--------------------------
1 file changed, 54 insertions(+), 60 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 1ec25ee71372..409cfa1d6d90 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -508,9 +508,7 @@ struct io_async_msghdr {
struct io_async_rw {
struct iovec fast_iov[UIO_FASTIOV];
- struct iovec *iov;
- ssize_t nr_segs;
- ssize_t size;
+ struct iov_iter iter;
struct wait_page_queue wpq;
};
@@ -915,8 +913,7 @@ static void io_file_put_work(struct work_struct *work);
static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
struct iovec **iovec, struct iov_iter *iter,
bool needs_lock);
-static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
- struct iovec *iovec, struct iovec *fast_iov,
+static int io_setup_async_rw(struct io_kiocb *req, struct iovec *iovec,
struct iov_iter *iter);
static struct kmem_cache *req_cachep;
@@ -2299,7 +2296,7 @@ static bool io_resubmit_prep(struct io_kiocb *req, int error)
ret = io_import_iovec(rw, req, &iovec, &iter, false);
if (ret < 0)
goto end_req;
- ret = io_setup_async_rw(req, ret, iovec, inline_vecs, &iter);
+ ret = io_setup_async_rw(req, iovec, &iter);
if (!ret)
return true;
kfree(iovec);
@@ -2820,6 +2817,13 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
ssize_t ret;
u8 opcode;
+ if (req->io) {
+ struct io_async_rw *iorw = &req->io->rw;
+
+ *iovec = NULL;
+ return iov_iter_count(&iorw->iter);
+ }
+
opcode = req->opcode;
if (opcode == IORING_OP_READ_FIXED || opcode == IORING_OP_WRITE_FIXED) {
*iovec = NULL;
@@ -2845,14 +2849,6 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
return ret < 0 ? ret : sqe_len;
}
- if (req->io) {
- struct io_async_rw *iorw = &req->io->rw;
-
- iov_iter_init(iter, rw, iorw->iov, iorw->nr_segs, iorw->size);
- *iovec = NULL;
- return iorw->size;
- }
-
if (req->flags & REQ_F_BUFFER_SELECT) {
ret = io_iov_buffer_select(req, *iovec, needs_lock);
if (!ret) {
@@ -2930,21 +2926,19 @@ static ssize_t loop_rw_iter(int rw, struct file *file, struct kiocb *kiocb,
return ret;
}
-static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
- struct iovec *iovec, struct iovec *fast_iov,
+static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec,
struct iov_iter *iter)
{
struct io_async_rw *rw = &req->io->rw;
- rw->nr_segs = iter->nr_segs;
- rw->size = io_size;
+ memcpy(&rw->iter, iter, sizeof(*iter));
if (!iovec) {
- rw->iov = rw->fast_iov;
- if (rw->iov != fast_iov)
- memcpy(rw->iov, fast_iov,
+ rw->iter.iov = rw->fast_iov;
+ if (rw->fast_iov != iter->iov)
+ memcpy(rw->fast_iov, iter->iov,
sizeof(struct iovec) * iter->nr_segs);
} else {
- rw->iov = iovec;
+ rw->iter.iov = iovec;
req->flags |= REQ_F_NEED_CLEANUP;
}
}
@@ -2963,8 +2957,7 @@ static int io_alloc_async_ctx(struct io_kiocb *req)
return __io_alloc_async_ctx(req);
}
-static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
- struct iovec *iovec, struct iovec *fast_iov,
+static int io_setup_async_rw(struct io_kiocb *req, struct iovec *iovec,
struct iov_iter *iter)
{
if (!io_op_defs[req->opcode].async_ctx)
@@ -2973,7 +2966,7 @@ static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
if (__io_alloc_async_ctx(req))
return -ENOMEM;
- io_req_map_rw(req, io_size, iovec, fast_iov, iter);
+ io_req_map_rw(req, iovec, iter);
}
return 0;
}
@@ -2981,18 +2974,19 @@ static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
static inline int io_rw_prep_async(struct io_kiocb *req, int rw,
bool force_nonblock)
{
- struct io_async_ctx *io = req->io;
- struct iov_iter iter;
+ struct io_async_rw *iorw = &req->io->rw;
ssize_t ret;
- io->rw.iov = io->rw.fast_iov;
+ iorw->iter.iov = iorw->fast_iov;
+ /* reset ->io around the iovec import, we don't want to use it */
req->io = NULL;
- ret = io_import_iovec(rw, req, &io->rw.iov, &iter, !force_nonblock);
- req->io = io;
+ ret = io_import_iovec(rw, req, (struct iovec **) &iorw->iter.iov,
+ &iorw->iter, !force_nonblock);
+ req->io = container_of(iorw, struct io_async_ctx, rw);
if (unlikely(ret < 0))
return ret;
- io_req_map_rw(req, ret, io->rw.iov, io->rw.fast_iov, &iter);
+ io_req_map_rw(req, iorw->iter.iov, &iorw->iter);
return 0;
}
@@ -3090,7 +3084,8 @@ static inline int kiocb_wait_page_queue_init(struct kiocb *kiocb,
* succeed, or in rare cases where it fails, we then fall back to using the
* async worker threads for a blocking retry.
*/
-static bool io_rw_should_retry(struct io_kiocb *req)
+static bool io_rw_should_retry(struct io_kiocb *req, struct iovec *iovec,
+ struct iovec *fast_iov, struct iov_iter *iter)
{
struct kiocb *kiocb = &req->rw.kiocb;
int ret;
@@ -3113,8 +3108,11 @@ static bool io_rw_should_retry(struct io_kiocb *req)
* If request type doesn't require req->io to defer in general,
* we need to allocate it here
*/
- if (!req->io && __io_alloc_async_ctx(req))
- return false;
+ if (!req->io) {
+ if (__io_alloc_async_ctx(req))
+ return false;
+ io_req_map_rw(req, iovec, iter);
+ }
ret = kiocb_wait_page_queue_init(kiocb, &req->io->rw.wpq,
io_async_buf_func, req);
@@ -3141,12 +3139,14 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
{
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
struct kiocb *kiocb = &req->rw.kiocb;
- struct iov_iter iter;
+ struct iov_iter __iter, *iter = &__iter;
size_t iov_count;
- ssize_t io_size, ret, ret2;
- unsigned long nr_segs;
+ ssize_t io_size, ret, ret2 = 0;
+
+ if (req->io)
+ iter = &req->io->rw.iter;
- ret = io_import_iovec(READ, req, &iovec, &iter, !force_nonblock);
+ ret = io_import_iovec(READ, req, &iovec, iter, !force_nonblock);
if (ret < 0)
return ret;
io_size = ret;
@@ -3160,30 +3160,26 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
if (force_nonblock && !io_file_supports_async(req->file, READ))
goto copy_iov;
- iov_count = iov_iter_count(&iter);
- nr_segs = iter.nr_segs;
+ iov_count = iov_iter_count(iter);
ret = rw_verify_area(READ, req->file, &kiocb->ki_pos, iov_count);
if (unlikely(ret))
goto out_free;
- ret2 = io_iter_do_read(req, &iter);
+ ret2 = io_iter_do_read(req, iter);
/* Catch -EAGAIN return for forced non-blocking submission */
if (!force_nonblock || (ret2 != -EAGAIN && ret2 != -EIO)) {
kiocb_done(kiocb, ret2, cs);
} else {
- iter.count = iov_count;
- iter.nr_segs = nr_segs;
copy_iov:
- ret = io_setup_async_rw(req, io_size, iovec, inline_vecs,
- &iter);
+ ret = io_setup_async_rw(req, iovec, iter);
if (ret)
goto out_free;
/* it's copied and will be cleaned with ->io */
iovec = NULL;
/* if we can retry, do so with the callbacks armed */
- if (io_rw_should_retry(req)) {
- ret2 = io_iter_do_read(req, &iter);
+ if (io_rw_should_retry(req, iovec, inline_vecs, iter)) {
+ ret2 = io_iter_do_read(req, iter);
if (ret2 == -EIOCBQUEUED) {
goto out_free;
} else if (ret2 != -EAGAIN) {
@@ -3223,12 +3219,14 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
{
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
struct kiocb *kiocb = &req->rw.kiocb;
- struct iov_iter iter;
+ struct iov_iter __iter, *iter = &__iter;
size_t iov_count;
ssize_t ret, ret2, io_size;
- unsigned long nr_segs;
- ret = io_import_iovec(WRITE, req, &iovec, &iter, !force_nonblock);
+ if (req->io)
+ iter = &req->io->rw.iter;
+
+ ret = io_import_iovec(WRITE, req, &iovec, iter, !force_nonblock);
if (ret < 0)
return ret;
io_size = ret;
@@ -3247,8 +3245,7 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
(req->flags & REQ_F_ISREG))
goto copy_iov;
- iov_count = iov_iter_count(&iter);
- nr_segs = iter.nr_segs;
+ iov_count = iov_iter_count(iter);
ret = rw_verify_area(WRITE, req->file, &kiocb->ki_pos, iov_count);
if (unlikely(ret))
goto out_free;
@@ -3269,9 +3266,9 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
kiocb->ki_flags |= IOCB_WRITE;
if (req->file->f_op->write_iter)
- ret2 = call_write_iter(req->file, kiocb, &iter);
+ ret2 = call_write_iter(req->file, kiocb, iter);
else if (req->file->f_op->write)
- ret2 = loop_rw_iter(WRITE, req->file, kiocb, &iter);
+ ret2 = loop_rw_iter(WRITE, req->file, kiocb, iter);
else
ret2 = -EINVAL;
@@ -3284,11 +3281,8 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
if (!force_nonblock || ret2 != -EAGAIN) {
kiocb_done(kiocb, ret2, cs);
} else {
- iter.count = iov_count;
- iter.nr_segs = nr_segs;
copy_iov:
- ret = io_setup_async_rw(req, io_size, iovec, inline_vecs,
- &iter);
+ ret = io_setup_async_rw(req, iovec, iter);
if (ret)
goto out_free;
/* it's copied and will be cleaned with ->io */
@@ -5583,8 +5577,8 @@ static void __io_clean_op(struct io_kiocb *req)
case IORING_OP_WRITEV:
case IORING_OP_WRITE_FIXED:
case IORING_OP_WRITE:
- if (io->rw.iov != io->rw.fast_iov)
- kfree(io->rw.iov);
+ if (io->rw.iter.iov != io->rw.fast_iov)
+ kfree(io->rw.iter.iov);
break;
case IORING_OP_RECVMSG:
case IORING_OP_SENDMSG:
--
2.28.0
next prev parent reply other threads:[~2020-08-14 19:58 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-14 19:54 [PATCHSET v2 0/2] io_uring: handle short reads internally Jens Axboe
2020-08-14 19:54 ` Jens Axboe [this message]
2020-08-14 19:54 ` [PATCH 2/2] io_uring: internally retry short reads Jens Axboe
2020-08-17 9:25 ` [PATCHSET v2 0/2] io_uring: handle short reads internally Stefan Metzmacher
2020-08-18 3:29 ` Jens Axboe
2020-08-18 4:12 ` Jens Axboe
2020-08-18 4:30 ` Jens Axboe
2020-08-18 7:40 ` Stefan Metzmacher
2020-08-18 14:44 ` Jens Axboe
2020-08-18 14:49 ` Anoop C S
2020-08-18 14:53 ` Jens Axboe
2020-08-18 15:23 ` Jens Axboe
[not found] ` <ad6cd95adb2e7622860fd9a80c19e48230ae2747.camel@cryptolab.net>
2020-08-19 8:31 ` Stefan Metzmacher
2020-08-19 12:48 ` Jens Axboe
-- strict thread matches above, loose matches on Subject: below --
2020-08-13 17:56 [PATCHSET " Jens Axboe
2020-08-13 17:56 ` [PATCH 1/2] io_uring: retain iov_iter state over io_read/io_write calls Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200814195449.533153-2-axboe@kernel.dk \
--to=axboe@kernel.dk \
--cc=david@fromorbit.com \
--cc=io-uring@vger.kernel.org \
--cc=jmoyer@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.