Skip to content

Commit d6f911a

Browse files
committed
io_uring/rw: add iovec recycling
Let the io_async_rw hold on to the iovec and reuse it, rather than always allocate and free them. Also enables KASAN for the iovec entries, so that reuse can be detected even while they are in the cache. While doing so, shrink io_async_rw by getting rid of the bigger embedded fast iovec. Since iovecs are being recycled now, shrink it from 8 to 1. This reduces the io_async_rw size from 264 to 160 bytes, a 40% reduction. Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent cca6571 commit d6f911a

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

io_uring/rw.c

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ static int __io_import_iovec(int ddir, struct io_kiocb *req,
8181
{
8282
const struct io_issue_def *def = &io_issue_defs[req->opcode];
8383
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
84+
struct iovec *iov;
8485
void __user *buf;
86+
int nr_segs, ret;
8587
size_t sqe_len;
8688

8789
buf = u64_to_user_ptr(rw->addr);
@@ -99,9 +101,24 @@ static int __io_import_iovec(int ddir, struct io_kiocb *req,
99101
return import_ubuf(ddir, buf, sqe_len, &io->iter);
100102
}
101103

102-
io->free_iovec = io->fast_iov;
103-
return __import_iovec(ddir, buf, sqe_len, UIO_FASTIOV, &io->free_iovec,
104-
&io->iter, req->ctx->compat);
104+
if (io->free_iovec) {
105+
nr_segs = io->free_iov_nr;
106+
iov = io->free_iovec;
107+
} else {
108+
iov = &io->fast_iov;
109+
nr_segs = 1;
110+
}
111+
ret = __import_iovec(ddir, buf, sqe_len, nr_segs, &iov, &io->iter,
112+
req->ctx->compat);
113+
if (unlikely(ret < 0))
114+
return ret;
115+
if (iov) {
116+
req->flags |= REQ_F_NEED_CLEANUP;
117+
io->free_iov_nr = io->iter.nr_segs;
118+
kfree(io->free_iovec);
119+
io->free_iovec = iov;
120+
}
121+
return 0;
105122
}
106123

107124
static inline int io_import_iovec(int rw, struct io_kiocb *req,
@@ -122,19 +139,24 @@ static void io_rw_iovec_free(struct io_async_rw *rw)
122139
{
123140
if (rw->free_iovec) {
124141
kfree(rw->free_iovec);
142+
rw->free_iov_nr = 0;
125143
rw->free_iovec = NULL;
126144
}
127145
}
128146

129147
static void io_rw_recycle(struct io_kiocb *req, unsigned int issue_flags)
130148
{
131149
struct io_async_rw *rw = req->async_data;
150+
struct iovec *iov;
132151

133152
if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) {
134153
io_rw_iovec_free(rw);
135154
return;
136155
}
156+
iov = rw->free_iovec;
137157
if (io_alloc_cache_put(&req->ctx->rw_cache, &rw->cache)) {
158+
if (iov)
159+
kasan_mempool_poison_object(iov);
138160
req->async_data = NULL;
139161
req->flags &= ~REQ_F_ASYNC_DATA;
140162
}
@@ -184,15 +206,21 @@ static int io_rw_alloc_async(struct io_kiocb *req)
184206
entry = io_alloc_cache_get(&ctx->rw_cache);
185207
if (entry) {
186208
rw = container_of(entry, struct io_async_rw, cache);
209+
if (rw->free_iovec) {
210+
kasan_mempool_unpoison_object(rw->free_iovec,
211+
rw->free_iov_nr * sizeof(struct iovec));
212+
req->flags |= REQ_F_NEED_CLEANUP;
213+
}
187214
req->flags |= REQ_F_ASYNC_DATA;
188215
req->async_data = rw;
189216
goto done;
190217
}
191218

192219
if (!io_alloc_async_data(req)) {
193220
rw = req->async_data;
194-
done:
195221
rw->free_iovec = NULL;
222+
rw->free_iov_nr = 0;
223+
done:
196224
rw->bytes_done = 0;
197225
return 0;
198226
}
@@ -1145,6 +1173,10 @@ void io_rw_cache_free(struct io_cache_entry *entry)
11451173
struct io_async_rw *rw;
11461174

11471175
rw = container_of(entry, struct io_async_rw, cache);
1148-
kfree(rw->free_iovec);
1176+
if (rw->free_iovec) {
1177+
kasan_mempool_unpoison_object(rw->free_iovec,
1178+
rw->free_iov_nr * sizeof(struct iovec));
1179+
io_rw_iovec_free(rw);
1180+
}
11491181
kfree(rw);
11501182
}

io_uring/rw.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ struct io_async_rw {
99
};
1010
struct iov_iter iter;
1111
struct iov_iter_state iter_state;
12-
struct iovec fast_iov[UIO_FASTIOV];
12+
struct iovec fast_iov;
1313
struct iovec *free_iovec;
14+
int free_iov_nr;
1415
struct wait_page_queue wpq;
1516
};
1617

0 commit comments

Comments
 (0)