Skip to content

Commit

Permalink
Merge tag 'io_uring-6.14-20250131' of git://git.kernel.dk/linux
Browse files Browse the repository at this point in the history
Pull more io_uring updates from Jens Axboe:

 - Series cleaning up the alloc cache changes from this merge window,
   and then another series on top making it better yet.

   This also solves an issue with KASAN_EXTRA_INFO, by making io_uring
   resilient to KASAN using parts of the freed struct for storage

 - Cleanups and simplications to buffer cloning and io resource node
   management

 - Fix an issue introduced in this merge window where READ/WRITE_ONCE
   was used on an atomic_t, which made some archs complain

 - Fix for an errant connect retry when the socket has been shut down

 - Fix for multishot and provided buffers

* tag 'io_uring-6.14-20250131' of git://git.kernel.dk/linux:
  io_uring/net: don't retry connect operation on EPOLLERR
  io_uring/rw: simplify io_rw_recycle()
  io_uring: remove !KASAN guards from cache free
  io_uring/net: extract io_send_select_buffer()
  io_uring/net: clean io_msg_copy_hdr()
  io_uring/net: make io_net_vec_assign() return void
  io_uring: add alloc_cache.c
  io_uring: dont ifdef io_alloc_cache_kasan()
  io_uring: include all deps for alloc_cache.h
  io_uring: fix multishots with selected buffers
  io_uring/register: use atomic_read/write for sq_flags migration
  io_uring/alloc_cache: get rid of _nocache() helper
  io_uring: get rid of alloc cache init_once handling
  io_uring/uring_cmd: cleanup struct io_uring_cmd_data layout
  io_uring/uring_cmd: use cached cmd_op in io_uring_cmd_sock()
  io_uring/msg_ring: don't leave potentially dangling ->tctx pointer
  io_uring/rsrc: Move lockdep assert from io_free_rsrc_node() to caller
  io_uring/rsrc: remove unused parameter ctx for io_rsrc_node_alloc()
  io_uring: clean up io_uring_register_get_file()
  io_uring/rsrc: Simplify buffer cloning by locking both rings
  • Loading branch information
torvalds committed Jan 31, 2025
2 parents 95d7e82 + 8c8492c commit c82da38
Show file tree
Hide file tree
Showing 21 changed files with 272 additions and 243 deletions.
2 changes: 1 addition & 1 deletion include/linux/io_uring/cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ struct io_uring_cmd {
};

struct io_uring_cmd_data {
struct io_uring_sqe sqes[2];
void *op_data;
struct io_uring_sqe sqes[2];
};

static inline const void *io_uring_sqe_cmd(const struct io_uring_sqe *sqe)
Expand Down
3 changes: 2 additions & 1 deletion include/linux/io_uring_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ struct io_alloc_cache {
void **entries;
unsigned int nr_cached;
unsigned int max_cached;
size_t elem_size;
unsigned int elem_size;
unsigned int init_clear;
};

struct io_ring_ctx {
Expand Down
2 changes: 1 addition & 1 deletion io_uring/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ obj-$(CONFIG_IO_URING) += io_uring.o opdef.o kbuf.o rsrc.o notif.o \
sync.o msg_ring.o advise.o openclose.o \
epoll.o statx.o timeout.o fdinfo.o \
cancel.o waitid.o register.o \
truncate.o memmap.o
truncate.o memmap.o alloc_cache.o
obj-$(CONFIG_IO_WQ) += io-wq.o
obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_NET_RX_BUSY_POLL) += napi.o
44 changes: 44 additions & 0 deletions io_uring/alloc_cache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0

#include "alloc_cache.h"

void io_alloc_cache_free(struct io_alloc_cache *cache,
void (*free)(const void *))
{
void *entry;

if (!cache->entries)
return;

while ((entry = io_alloc_cache_get(cache)) != NULL)
free(entry);

kvfree(cache->entries);
cache->entries = NULL;
}

/* returns false if the cache was initialized properly */
bool io_alloc_cache_init(struct io_alloc_cache *cache,
unsigned max_nr, unsigned int size,
unsigned int init_bytes)
{
cache->entries = kvmalloc_array(max_nr, sizeof(void *), GFP_KERNEL);
if (!cache->entries)
return true;

cache->nr_cached = 0;
cache->max_cached = max_nr;
cache->elem_size = size;
cache->init_clear = init_bytes;
return false;
}

void *io_cache_alloc_new(struct io_alloc_cache *cache, gfp_t gfp)
{
void *obj;

obj = kmalloc(cache->elem_size, gfp);
if (obj && cache->init_clear)
memset(obj, 0, cache->init_clear);
return obj;
}
69 changes: 33 additions & 36 deletions io_uring/alloc_cache.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
#ifndef IOU_ALLOC_CACHE_H
#define IOU_ALLOC_CACHE_H

#include <linux/io_uring_types.h>

/*
* Don't allow the cache to grow beyond this size.
*/
#define IO_ALLOC_CACHE_MAX 128

void io_alloc_cache_free(struct io_alloc_cache *cache,
void (*free)(const void *));
bool io_alloc_cache_init(struct io_alloc_cache *cache,
unsigned max_nr, unsigned int size,
unsigned int init_bytes);

void *io_cache_alloc_new(struct io_alloc_cache *cache, gfp_t gfp);

static inline void io_alloc_cache_kasan(struct iovec **iov, int *nr)
{
if (IS_ENABLED(CONFIG_KASAN)) {
kfree(*iov);
*iov = NULL;
*nr = 0;
}
}

static inline bool io_alloc_cache_put(struct io_alloc_cache *cache,
void *entry)
{
Expand All @@ -23,52 +42,30 @@ static inline void *io_alloc_cache_get(struct io_alloc_cache *cache)
if (cache->nr_cached) {
void *entry = cache->entries[--cache->nr_cached];

/*
* If KASAN is enabled, always clear the initial bytes that
* must be zeroed post alloc, in case any of them overlap
* with KASAN storage.
*/
#if defined(CONFIG_KASAN)
kasan_mempool_unpoison_object(entry, cache->elem_size);
if (cache->init_clear)
memset(entry, 0, cache->init_clear);
#endif
return entry;
}

return NULL;
}

static inline void *io_cache_alloc(struct io_alloc_cache *cache, gfp_t gfp,
void (*init_once)(void *obj))
static inline void *io_cache_alloc(struct io_alloc_cache *cache, gfp_t gfp)
{
if (unlikely(!cache->nr_cached)) {
void *obj = kmalloc(cache->elem_size, gfp);
void *obj;

if (obj && init_once)
init_once(obj);
obj = io_alloc_cache_get(cache);
if (obj)
return obj;
}
return io_alloc_cache_get(cache);
return io_cache_alloc_new(cache, gfp);
}

/* returns false if the cache was initialized properly */
static inline bool io_alloc_cache_init(struct io_alloc_cache *cache,
unsigned max_nr, size_t size)
{
cache->entries = kvmalloc_array(max_nr, sizeof(void *), GFP_KERNEL);
if (cache->entries) {
cache->nr_cached = 0;
cache->max_cached = max_nr;
cache->elem_size = size;
return false;
}
return true;
}

static inline void io_alloc_cache_free(struct io_alloc_cache *cache,
void (*free)(const void *))
{
void *entry;

if (!cache->entries)
return;

while ((entry = io_alloc_cache_get(cache)) != NULL)
free(entry);

kvfree(cache->entries);
cache->entries = NULL;
}
#endif
2 changes: 1 addition & 1 deletion io_uring/filetable.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
if (slot_index >= ctx->file_table.data.nr)
return -EINVAL;

node = io_rsrc_node_alloc(ctx, IORING_RSRC_FILE);
node = io_rsrc_node_alloc(IORING_RSRC_FILE);
if (!node)
return -ENOMEM;

Expand Down
4 changes: 2 additions & 2 deletions io_uring/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct io_futex_data {
bool io_futex_cache_init(struct io_ring_ctx *ctx)
{
return io_alloc_cache_init(&ctx->futex_cache, IO_FUTEX_ALLOC_CACHE_MAX,
sizeof(struct io_futex_data));
sizeof(struct io_futex_data), 0);
}

void io_futex_cache_free(struct io_ring_ctx *ctx)
Expand Down Expand Up @@ -320,7 +320,7 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
}

io_ring_submit_lock(ctx, issue_flags);
ifd = io_cache_alloc(&ctx->futex_cache, GFP_NOWAIT, NULL);
ifd = io_cache_alloc(&ctx->futex_cache, GFP_NOWAIT);
if (!ifd) {
ret = -ENOMEM;
goto done_unlock;
Expand Down
12 changes: 7 additions & 5 deletions io_uring/io_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,16 +315,18 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
INIT_LIST_HEAD(&ctx->cq_overflow_list);
INIT_LIST_HEAD(&ctx->io_buffers_cache);
ret = io_alloc_cache_init(&ctx->apoll_cache, IO_POLL_ALLOC_CACHE_MAX,
sizeof(struct async_poll));
sizeof(struct async_poll), 0);
ret |= io_alloc_cache_init(&ctx->netmsg_cache, IO_ALLOC_CACHE_MAX,
sizeof(struct io_async_msghdr));
sizeof(struct io_async_msghdr),
offsetof(struct io_async_msghdr, clear));
ret |= io_alloc_cache_init(&ctx->rw_cache, IO_ALLOC_CACHE_MAX,
sizeof(struct io_async_rw));
sizeof(struct io_async_rw),
offsetof(struct io_async_rw, clear));
ret |= io_alloc_cache_init(&ctx->uring_cache, IO_ALLOC_CACHE_MAX,
sizeof(struct io_uring_cmd_data));
sizeof(struct io_uring_cmd_data), 0);
spin_lock_init(&ctx->msg_lock);
ret |= io_alloc_cache_init(&ctx->msg_cache, IO_ALLOC_CACHE_MAX,
sizeof(struct io_kiocb));
sizeof(struct io_kiocb), 0);
ret |= io_futex_cache_init(ctx);
if (ret)
goto free_ref;
Expand Down
21 changes: 8 additions & 13 deletions io_uring/io_uring.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,21 +226,16 @@ static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags)
}

static inline void *io_uring_alloc_async_data(struct io_alloc_cache *cache,
struct io_kiocb *req,
void (*init_once)(void *obj))
struct io_kiocb *req)
{
req->async_data = io_cache_alloc(cache, GFP_KERNEL, init_once);
if (req->async_data)
req->flags |= REQ_F_ASYNC_DATA;
return req->async_data;
}
if (cache) {
req->async_data = io_cache_alloc(cache, GFP_KERNEL);
} else {
const struct io_issue_def *def = &io_issue_defs[req->opcode];

static inline void *io_uring_alloc_async_data_nocache(struct io_kiocb *req)
{
const struct io_issue_def *def = &io_issue_defs[req->opcode];

WARN_ON_ONCE(!def->async_size);
req->async_data = kmalloc(def->async_size, GFP_KERNEL);
WARN_ON_ONCE(!def->async_size);
req->async_data = kmalloc(def->async_size, GFP_KERNEL);
}
if (req->async_data)
req->flags |= REQ_F_ASYNC_DATA;
return req->async_data;
Expand Down
4 changes: 2 additions & 2 deletions io_uring/msg_ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ static void io_msg_tw_complete(struct io_kiocb *req, struct io_tw_state *ts)
static int io_msg_remote_post(struct io_ring_ctx *ctx, struct io_kiocb *req,
int res, u32 cflags, u64 user_data)
{
req->tctx = READ_ONCE(ctx->submitter_task->io_uring);
if (!req->tctx) {
if (!READ_ONCE(ctx->submitter_task)) {
kmem_cache_free(req_cachep, req);
return -EOWNERDEAD;
}
req->cqe.user_data = user_data;
io_req_set_res(req, res, cflags);
percpu_ref_get(&ctx->refs);
req->ctx = ctx;
req->tctx = NULL;
req->io_task_work.func = io_msg_tw_complete;
io_req_task_work_add_remote(req, ctx, IOU_F_TWQ_LAZY_WAKE);
return 0;
Expand Down
Loading

0 comments on commit c82da38

Please sign in to comment.