Skip to content

Commit ff6165b

Browse files
committed
io_uring: retain iov_iter state over io_read/io_write calls
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 <[email protected]>
1 parent ebf0d10 commit ff6165b

File tree

1 file changed

+70
-66
lines changed

1 file changed

+70
-66
lines changed

fs/io_uring.c

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -508,9 +508,8 @@ struct io_async_msghdr {
508508

509509
struct io_async_rw {
510510
struct iovec fast_iov[UIO_FASTIOV];
511-
struct iovec *iov;
512-
ssize_t nr_segs;
513-
ssize_t size;
511+
const struct iovec *free_iovec;
512+
struct iov_iter iter;
514513
struct wait_page_queue wpq;
515514
};
516515

@@ -915,8 +914,8 @@ static void io_file_put_work(struct work_struct *work);
915914
static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
916915
struct iovec **iovec, struct iov_iter *iter,
917916
bool needs_lock);
918-
static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
919-
struct iovec *iovec, struct iovec *fast_iov,
917+
static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
918+
const struct iovec *fast_iov,
920919
struct iov_iter *iter);
921920

922921
static struct kmem_cache *req_cachep;
@@ -2299,7 +2298,7 @@ static bool io_resubmit_prep(struct io_kiocb *req, int error)
22992298
ret = io_import_iovec(rw, req, &iovec, &iter, false);
23002299
if (ret < 0)
23012300
goto end_req;
2302-
ret = io_setup_async_rw(req, ret, iovec, inline_vecs, &iter);
2301+
ret = io_setup_async_rw(req, iovec, inline_vecs, &iter);
23032302
if (!ret)
23042303
return true;
23052304
kfree(iovec);
@@ -2820,6 +2819,13 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
28202819
ssize_t ret;
28212820
u8 opcode;
28222821

2822+
if (req->io) {
2823+
struct io_async_rw *iorw = &req->io->rw;
2824+
2825+
*iovec = NULL;
2826+
return iov_iter_count(&iorw->iter);
2827+
}
2828+
28232829
opcode = req->opcode;
28242830
if (opcode == IORING_OP_READ_FIXED || opcode == IORING_OP_WRITE_FIXED) {
28252831
*iovec = NULL;
@@ -2845,14 +2851,6 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
28452851
return ret < 0 ? ret : sqe_len;
28462852
}
28472853

2848-
if (req->io) {
2849-
struct io_async_rw *iorw = &req->io->rw;
2850-
2851-
iov_iter_init(iter, rw, iorw->iov, iorw->nr_segs, iorw->size);
2852-
*iovec = NULL;
2853-
return iorw->size;
2854-
}
2855-
28562854
if (req->flags & REQ_F_BUFFER_SELECT) {
28572855
ret = io_iov_buffer_select(req, *iovec, needs_lock);
28582856
if (!ret) {
@@ -2930,21 +2928,29 @@ static ssize_t loop_rw_iter(int rw, struct file *file, struct kiocb *kiocb,
29302928
return ret;
29312929
}
29322930

2933-
static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
2934-
struct iovec *iovec, struct iovec *fast_iov,
2935-
struct iov_iter *iter)
2931+
static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec,
2932+
const struct iovec *fast_iov, struct iov_iter *iter)
29362933
{
29372934
struct io_async_rw *rw = &req->io->rw;
29382935

2939-
rw->nr_segs = iter->nr_segs;
2940-
rw->size = io_size;
2936+
memcpy(&rw->iter, iter, sizeof(*iter));
2937+
rw->free_iovec = NULL;
2938+
/* can only be fixed buffers, no need to do anything */
2939+
if (iter->type == ITER_BVEC)
2940+
return;
29412941
if (!iovec) {
2942-
rw->iov = rw->fast_iov;
2943-
if (rw->iov != fast_iov)
2944-
memcpy(rw->iov, fast_iov,
2942+
unsigned iov_off = 0;
2943+
2944+
rw->iter.iov = rw->fast_iov;
2945+
if (iter->iov != fast_iov) {
2946+
iov_off = iter->iov - fast_iov;
2947+
rw->iter.iov += iov_off;
2948+
}
2949+
if (rw->fast_iov != fast_iov)
2950+
memcpy(rw->fast_iov + iov_off, fast_iov + iov_off,
29452951
sizeof(struct iovec) * iter->nr_segs);
29462952
} else {
2947-
rw->iov = iovec;
2953+
rw->free_iovec = iovec;
29482954
req->flags |= REQ_F_NEED_CLEANUP;
29492955
}
29502956
}
@@ -2963,8 +2969,8 @@ static int io_alloc_async_ctx(struct io_kiocb *req)
29632969
return __io_alloc_async_ctx(req);
29642970
}
29652971

2966-
static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
2967-
struct iovec *iovec, struct iovec *fast_iov,
2972+
static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
2973+
const struct iovec *fast_iov,
29682974
struct iov_iter *iter)
29692975
{
29702976
if (!io_op_defs[req->opcode].async_ctx)
@@ -2973,26 +2979,27 @@ static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
29732979
if (__io_alloc_async_ctx(req))
29742980
return -ENOMEM;
29752981

2976-
io_req_map_rw(req, io_size, iovec, fast_iov, iter);
2982+
io_req_map_rw(req, iovec, fast_iov, iter);
29772983
}
29782984
return 0;
29792985
}
29802986

29812987
static inline int io_rw_prep_async(struct io_kiocb *req, int rw,
29822988
bool force_nonblock)
29832989
{
2984-
struct io_async_ctx *io = req->io;
2985-
struct iov_iter iter;
2990+
struct io_async_rw *iorw = &req->io->rw;
29862991
ssize_t ret;
29872992

2988-
io->rw.iov = io->rw.fast_iov;
2993+
iorw->iter.iov = iorw->fast_iov;
2994+
/* reset ->io around the iovec import, we don't want to use it */
29892995
req->io = NULL;
2990-
ret = io_import_iovec(rw, req, &io->rw.iov, &iter, !force_nonblock);
2991-
req->io = io;
2996+
ret = io_import_iovec(rw, req, (struct iovec **) &iorw->iter.iov,
2997+
&iorw->iter, !force_nonblock);
2998+
req->io = container_of(iorw, struct io_async_ctx, rw);
29922999
if (unlikely(ret < 0))
29933000
return ret;
29943001

2995-
io_req_map_rw(req, ret, io->rw.iov, io->rw.fast_iov, &iter);
3002+
io_req_map_rw(req, iorw->iter.iov, iorw->fast_iov, &iorw->iter);
29963003
return 0;
29973004
}
29983005

@@ -3090,7 +3097,8 @@ static inline int kiocb_wait_page_queue_init(struct kiocb *kiocb,
30903097
* succeed, or in rare cases where it fails, we then fall back to using the
30913098
* async worker threads for a blocking retry.
30923099
*/
3093-
static bool io_rw_should_retry(struct io_kiocb *req)
3100+
static bool io_rw_should_retry(struct io_kiocb *req, struct iovec *iovec,
3101+
struct iovec *fast_iov, struct iov_iter *iter)
30943102
{
30953103
struct kiocb *kiocb = &req->rw.kiocb;
30963104
int ret;
@@ -3113,8 +3121,11 @@ static bool io_rw_should_retry(struct io_kiocb *req)
31133121
* If request type doesn't require req->io to defer in general,
31143122
* we need to allocate it here
31153123
*/
3116-
if (!req->io && __io_alloc_async_ctx(req))
3117-
return false;
3124+
if (!req->io) {
3125+
if (__io_alloc_async_ctx(req))
3126+
return false;
3127+
io_req_map_rw(req, iovec, fast_iov, iter);
3128+
}
31183129

31193130
ret = kiocb_wait_page_queue_init(kiocb, &req->io->rw.wpq,
31203131
io_async_buf_func, req);
@@ -3141,12 +3152,14 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
31413152
{
31423153
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
31433154
struct kiocb *kiocb = &req->rw.kiocb;
3144-
struct iov_iter iter;
3155+
struct iov_iter __iter, *iter = &__iter;
31453156
size_t iov_count;
3146-
ssize_t io_size, ret, ret2;
3147-
unsigned long nr_segs;
3157+
ssize_t io_size, ret, ret2 = 0;
3158+
3159+
if (req->io)
3160+
iter = &req->io->rw.iter;
31483161

3149-
ret = io_import_iovec(READ, req, &iovec, &iter, !force_nonblock);
3162+
ret = io_import_iovec(READ, req, &iovec, iter, !force_nonblock);
31503163
if (ret < 0)
31513164
return ret;
31523165
io_size = ret;
@@ -3160,30 +3173,26 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
31603173
if (force_nonblock && !io_file_supports_async(req->file, READ))
31613174
goto copy_iov;
31623175

3163-
iov_count = iov_iter_count(&iter);
3164-
nr_segs = iter.nr_segs;
3176+
iov_count = iov_iter_count(iter);
31653177
ret = rw_verify_area(READ, req->file, &kiocb->ki_pos, iov_count);
31663178
if (unlikely(ret))
31673179
goto out_free;
31683180

3169-
ret2 = io_iter_do_read(req, &iter);
3181+
ret2 = io_iter_do_read(req, iter);
31703182

31713183
/* Catch -EAGAIN return for forced non-blocking submission */
31723184
if (!force_nonblock || (ret2 != -EAGAIN && ret2 != -EIO)) {
31733185
kiocb_done(kiocb, ret2, cs);
31743186
} else {
3175-
iter.count = iov_count;
3176-
iter.nr_segs = nr_segs;
31773187
copy_iov:
3178-
ret = io_setup_async_rw(req, io_size, iovec, inline_vecs,
3179-
&iter);
3188+
ret = io_setup_async_rw(req, iovec, inline_vecs, iter);
31803189
if (ret)
31813190
goto out_free;
31823191
/* it's copied and will be cleaned with ->io */
31833192
iovec = NULL;
31843193
/* if we can retry, do so with the callbacks armed */
3185-
if (io_rw_should_retry(req)) {
3186-
ret2 = io_iter_do_read(req, &iter);
3194+
if (io_rw_should_retry(req, iovec, inline_vecs, iter)) {
3195+
ret2 = io_iter_do_read(req, iter);
31873196
if (ret2 == -EIOCBQUEUED) {
31883197
goto out_free;
31893198
} else if (ret2 != -EAGAIN) {
@@ -3223,12 +3232,14 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
32233232
{
32243233
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
32253234
struct kiocb *kiocb = &req->rw.kiocb;
3226-
struct iov_iter iter;
3235+
struct iov_iter __iter, *iter = &__iter;
32273236
size_t iov_count;
32283237
ssize_t ret, ret2, io_size;
3229-
unsigned long nr_segs;
32303238

3231-
ret = io_import_iovec(WRITE, req, &iovec, &iter, !force_nonblock);
3239+
if (req->io)
3240+
iter = &req->io->rw.iter;
3241+
3242+
ret = io_import_iovec(WRITE, req, &iovec, iter, !force_nonblock);
32323243
if (ret < 0)
32333244
return ret;
32343245
io_size = ret;
@@ -3247,8 +3258,7 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
32473258
(req->flags & REQ_F_ISREG))
32483259
goto copy_iov;
32493260

3250-
iov_count = iov_iter_count(&iter);
3251-
nr_segs = iter.nr_segs;
3261+
iov_count = iov_iter_count(iter);
32523262
ret = rw_verify_area(WRITE, req->file, &kiocb->ki_pos, iov_count);
32533263
if (unlikely(ret))
32543264
goto out_free;
@@ -3269,9 +3279,9 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
32693279
kiocb->ki_flags |= IOCB_WRITE;
32703280

32713281
if (req->file->f_op->write_iter)
3272-
ret2 = call_write_iter(req->file, kiocb, &iter);
3282+
ret2 = call_write_iter(req->file, kiocb, iter);
32733283
else if (req->file->f_op->write)
3274-
ret2 = loop_rw_iter(WRITE, req->file, kiocb, &iter);
3284+
ret2 = loop_rw_iter(WRITE, req->file, kiocb, iter);
32753285
else
32763286
ret2 = -EINVAL;
32773287

@@ -3284,16 +3294,10 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
32843294
if (!force_nonblock || ret2 != -EAGAIN) {
32853295
kiocb_done(kiocb, ret2, cs);
32863296
} else {
3287-
iter.count = iov_count;
3288-
iter.nr_segs = nr_segs;
32893297
copy_iov:
3290-
ret = io_setup_async_rw(req, io_size, iovec, inline_vecs,
3291-
&iter);
3292-
if (ret)
3293-
goto out_free;
3294-
/* it's copied and will be cleaned with ->io */
3295-
iovec = NULL;
3296-
return -EAGAIN;
3298+
ret = io_setup_async_rw(req, iovec, inline_vecs, iter);
3299+
if (!ret)
3300+
return -EAGAIN;
32973301
}
32983302
out_free:
32993303
if (iovec)
@@ -5583,8 +5587,8 @@ static void __io_clean_op(struct io_kiocb *req)
55835587
case IORING_OP_WRITEV:
55845588
case IORING_OP_WRITE_FIXED:
55855589
case IORING_OP_WRITE:
5586-
if (io->rw.iov != io->rw.fast_iov)
5587-
kfree(io->rw.iov);
5590+
if (io->rw.free_iovec)
5591+
kfree(io->rw.free_iovec);
55885592
break;
55895593
case IORING_OP_RECVMSG:
55905594
case IORING_OP_SENDMSG:

0 commit comments

Comments
 (0)