Skip to content

Commit 41edf1a

Browse files
isilenceaxboe
authored andcommitted
io_uring: keep table of pointers to ubufs
Instead of keeping a table of ubufs convert them into pointers to ubuf, so we can atomically read one pointer and be sure that the content of ubuf won't change. Because it was already dynamically allocating imu->bvec, throw both imu and bvec into a single structure so they can be allocated together. Signed-off-by: Pavel Begunkov <[email protected]> Link: https://lore.kernel.org/r/b96efa4c5febadeccf41d0e849ac099f4c83b0d3.1619356238.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <[email protected]>
1 parent c3bdad0 commit 41edf1a

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

fs/io_uring.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,9 @@ enum io_uring_cmd_flags {
195195
struct io_mapped_ubuf {
196196
u64 ubuf;
197197
u64 ubuf_end;
198-
struct bio_vec *bvec;
199198
unsigned int nr_bvecs;
200199
unsigned long acct_pages;
200+
struct bio_vec bvec[];
201201
};
202202

203203
struct io_ring_ctx;
@@ -405,7 +405,7 @@ struct io_ring_ctx {
405405

406406
/* if used, fixed mapped user buffers */
407407
unsigned nr_user_bufs;
408-
struct io_mapped_ubuf *user_bufs;
408+
struct io_mapped_ubuf **user_bufs;
409409

410410
struct user_struct *user;
411411

@@ -2760,7 +2760,7 @@ static int io_import_fixed(struct io_kiocb *req, int rw, struct iov_iter *iter)
27602760
if (unlikely(buf_index >= ctx->nr_user_bufs))
27612761
return -EFAULT;
27622762
index = array_index_nospec(buf_index, ctx->nr_user_bufs);
2763-
imu = &ctx->user_bufs[index];
2763+
imu = ctx->user_bufs[index];
27642764
buf_addr = req->rw.addr;
27652765

27662766
if (unlikely(check_add_overflow(buf_addr, (u64)len, &buf_end)))
@@ -8081,16 +8081,17 @@ static unsigned long rings_size(unsigned sq_entries, unsigned cq_entries,
80818081
return off;
80828082
}
80838083

8084-
static void io_buffer_unmap(struct io_ring_ctx *ctx, struct io_mapped_ubuf *imu)
8084+
static void io_buffer_unmap(struct io_ring_ctx *ctx, struct io_mapped_ubuf **slot)
80858085
{
8086+
struct io_mapped_ubuf *imu = *slot;
80868087
unsigned int i;
80878088

80888089
for (i = 0; i < imu->nr_bvecs; i++)
80898090
unpin_user_page(imu->bvec[i].bv_page);
80908091
if (imu->acct_pages)
80918092
io_unaccount_mem(ctx, imu->acct_pages);
8092-
kvfree(imu->bvec);
8093-
imu->nr_bvecs = 0;
8093+
kvfree(imu);
8094+
*slot = NULL;
80948095
}
80958096

80968097
static int io_sqe_buffers_unregister(struct io_ring_ctx *ctx)
@@ -8157,7 +8158,7 @@ static bool headpage_already_acct(struct io_ring_ctx *ctx, struct page **pages,
81578158

81588159
/* check previously registered pages */
81598160
for (i = 0; i < ctx->nr_user_bufs; i++) {
8160-
struct io_mapped_ubuf *imu = &ctx->user_bufs[i];
8161+
struct io_mapped_ubuf *imu = ctx->user_bufs[i];
81618162

81628163
for (j = 0; j < imu->nr_bvecs; j++) {
81638164
if (!PageCompound(imu->bvec[j].bv_page))
@@ -8202,9 +8203,10 @@ static int io_buffer_account_pin(struct io_ring_ctx *ctx, struct page **pages,
82028203
}
82038204

82048205
static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
8205-
struct io_mapped_ubuf *imu,
8206+
struct io_mapped_ubuf **pimu,
82068207
struct page **last_hpage)
82078208
{
8209+
struct io_mapped_ubuf *imu = NULL;
82088210
struct vm_area_struct **vmas = NULL;
82098211
struct page **pages = NULL;
82108212
unsigned long off, start, end, ubuf;
@@ -8216,6 +8218,7 @@ static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
82168218
start = ubuf >> PAGE_SHIFT;
82178219
nr_pages = end - start;
82188220

8221+
*pimu = NULL;
82198222
ret = -ENOMEM;
82208223

82218224
pages = kvmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
@@ -8227,8 +8230,7 @@ static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
82278230
if (!vmas)
82288231
goto done;
82298232

8230-
imu->bvec = kvmalloc_array(nr_pages, sizeof(struct bio_vec),
8231-
GFP_KERNEL);
8233+
imu = kvmalloc(struct_size(imu, bvec, nr_pages), GFP_KERNEL);
82328234
if (!imu->bvec)
82338235
goto done;
82348236

@@ -8258,14 +8260,12 @@ static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
82588260
*/
82598261
if (pret > 0)
82608262
unpin_user_pages(pages, pret);
8261-
kvfree(imu->bvec);
82628263
goto done;
82638264
}
82648265

82658266
ret = io_buffer_account_pin(ctx, pages, pret, imu, last_hpage);
82668267
if (ret) {
82678268
unpin_user_pages(pages, pret);
8268-
kvfree(imu->bvec);
82698269
goto done;
82708270
}
82718271

@@ -8285,8 +8285,11 @@ static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
82858285
imu->ubuf = ubuf;
82868286
imu->ubuf_end = ubuf + iov->iov_len;
82878287
imu->nr_bvecs = nr_pages;
8288+
*pimu = imu;
82888289
ret = 0;
82898290
done:
8291+
if (ret)
8292+
kvfree(imu);
82908293
kvfree(pages);
82918294
kvfree(vmas);
82928295
return ret;
@@ -8336,15 +8339,15 @@ static int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
83368339
return ret;
83378340

83388341
for (i = 0; i < nr_args; i++, ctx->nr_user_bufs++) {
8339-
struct io_mapped_ubuf *imu = &ctx->user_bufs[i];
8340-
83418342
ret = io_copy_iov(ctx, &iov, arg, i);
83428343
if (ret)
83438344
break;
83448345
ret = io_buffer_validate(&iov);
83458346
if (ret)
83468347
break;
8347-
ret = io_sqe_buffer_register(ctx, &iov, imu, &last_hpage);
8348+
8349+
ret = io_sqe_buffer_register(ctx, &iov, &ctx->user_bufs[i],
8350+
&last_hpage);
83488351
if (ret)
83498352
break;
83508353
}
@@ -9291,7 +9294,7 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
92919294
}
92929295
seq_printf(m, "UserBufs:\t%u\n", ctx->nr_user_bufs);
92939296
for (i = 0; has_lock && i < ctx->nr_user_bufs; i++) {
9294-
struct io_mapped_ubuf *buf = &ctx->user_bufs[i];
9297+
struct io_mapped_ubuf *buf = ctx->user_bufs[i];
92959298
unsigned int len = buf->ubuf_end - buf->ubuf;
92969299

92979300
seq_printf(m, "%5u: 0x%llx/%u\n", i, buf->ubuf, len);

0 commit comments

Comments
 (0)