Commit c82da38b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'io_uring-6.14-20250131' of git://git.kernel.dk/linux

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
parents 95d7e822 8c8492ca
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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)
+2 −1
Original line number Diff line number Diff line
@@ -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 {
+1 −1
Original line number Diff line number Diff line
@@ -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

io_uring/alloc_cache.c

0 → 100644
+44 −0
Original line number Diff line number Diff line
// 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;
}
+33 −36
Original line number Diff line number Diff line
#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)
{
@@ -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
Loading