xref: /linux-6.15/io_uring/alloc_cache.h (revision fa359552)
19b797a37SJens Axboe #ifndef IOU_ALLOC_CACHE_H
29b797a37SJens Axboe #define IOU_ALLOC_CACHE_H
39b797a37SJens Axboe 
49731bc98SJens Axboe /*
59731bc98SJens Axboe  * Don't allow the cache to grow beyond this size.
69731bc98SJens Axboe  */
70ae9b9a1SJens Axboe #define IO_ALLOC_CACHE_MAX	128
89731bc98SJens Axboe 
9*fa359552SJens Axboe #if defined(CONFIG_KASAN)
10*fa359552SJens Axboe static inline void io_alloc_cache_kasan(struct iovec **iov, int *nr)
11*fa359552SJens Axboe {
12*fa359552SJens Axboe 	kfree(*iov);
13*fa359552SJens Axboe 	*iov = NULL;
14*fa359552SJens Axboe 	*nr = 0;
15*fa359552SJens Axboe }
16*fa359552SJens Axboe #else
17*fa359552SJens Axboe static inline void io_alloc_cache_kasan(struct iovec **iov, int *nr)
18*fa359552SJens Axboe {
19*fa359552SJens Axboe }
20*fa359552SJens Axboe #endif
21*fa359552SJens Axboe 
229731bc98SJens Axboe static inline bool io_alloc_cache_put(struct io_alloc_cache *cache,
23414d0f45SJens Axboe 				      void *entry)
249b797a37SJens Axboe {
2569bbc6adSPavel Begunkov 	if (cache->nr_cached < cache->max_cached) {
26414d0f45SJens Axboe 		if (!kasan_mempool_poison_object(entry))
27414d0f45SJens Axboe 			return false;
28414d0f45SJens Axboe 		cache->entries[cache->nr_cached++] = entry;
299731bc98SJens Axboe 		return true;
309731bc98SJens Axboe 	}
319731bc98SJens Axboe 	return false;
329b797a37SJens Axboe }
339b797a37SJens Axboe 
34414d0f45SJens Axboe static inline void *io_alloc_cache_get(struct io_alloc_cache *cache)
35528407b1SPavel Begunkov {
36414d0f45SJens Axboe 	if (cache->nr_cached) {
37414d0f45SJens Axboe 		void *entry = cache->entries[--cache->nr_cached];
38528407b1SPavel Begunkov 
39*fa359552SJens Axboe 		/*
40*fa359552SJens Axboe 		 * If KASAN is enabled, always clear the initial bytes that
41*fa359552SJens Axboe 		 * must be zeroed post alloc, in case any of them overlap
42*fa359552SJens Axboe 		 * with KASAN storage.
43*fa359552SJens Axboe 		 */
44*fa359552SJens Axboe #if defined(CONFIG_KASAN)
458ab3b097SAndrey Konovalov 		kasan_mempool_unpoison_object(entry, cache->elem_size);
46*fa359552SJens Axboe 		if (cache->init_clear)
47*fa359552SJens Axboe 			memset(entry, 0, cache->init_clear);
48*fa359552SJens Axboe #endif
49efba1a9eSBreno Leitao 		return entry;
509b797a37SJens Axboe 	}
519b797a37SJens Axboe 
529b797a37SJens Axboe 	return NULL;
539b797a37SJens Axboe }
549b797a37SJens Axboe 
55*fa359552SJens Axboe static inline void *io_cache_alloc(struct io_alloc_cache *cache, gfp_t gfp)
56479b2f45SGabriel Krisman Bertazi {
57*fa359552SJens Axboe 	void *obj;
58479b2f45SGabriel Krisman Bertazi 
59*fa359552SJens Axboe 	obj = io_alloc_cache_get(cache);
60*fa359552SJens Axboe 	if (obj)
61479b2f45SGabriel Krisman Bertazi 		return obj;
62*fa359552SJens Axboe 
63*fa359552SJens Axboe 	obj = kmalloc(cache->elem_size, gfp);
64*fa359552SJens Axboe 	if (obj && cache->init_clear)
65*fa359552SJens Axboe 		memset(obj, 0, cache->init_clear);
66*fa359552SJens Axboe 	return obj;
67479b2f45SGabriel Krisman Bertazi }
68479b2f45SGabriel Krisman Bertazi 
69414d0f45SJens Axboe /* returns false if the cache was initialized properly */
70414d0f45SJens Axboe static inline bool io_alloc_cache_init(struct io_alloc_cache *cache,
71*fa359552SJens Axboe 				       unsigned max_nr, unsigned int size,
72*fa359552SJens Axboe 				       unsigned int init_bytes)
739b797a37SJens Axboe {
74414d0f45SJens Axboe 	cache->entries = kvmalloc_array(max_nr, sizeof(void *), GFP_KERNEL);
75414d0f45SJens Axboe 	if (cache->entries) {
769731bc98SJens Axboe 		cache->nr_cached = 0;
7769bbc6adSPavel Begunkov 		cache->max_cached = max_nr;
78e1fe7ee8SBreno Leitao 		cache->elem_size = size;
79*fa359552SJens Axboe 		cache->init_clear = init_bytes;
80414d0f45SJens Axboe 		return false;
81414d0f45SJens Axboe 	}
82414d0f45SJens Axboe 	return true;
839b797a37SJens Axboe }
849b797a37SJens Axboe 
859b797a37SJens Axboe static inline void io_alloc_cache_free(struct io_alloc_cache *cache,
86414d0f45SJens Axboe 				       void (*free)(const void *))
879b797a37SJens Axboe {
88414d0f45SJens Axboe 	void *entry;
899b797a37SJens Axboe 
90414d0f45SJens Axboe 	if (!cache->entries)
91414d0f45SJens Axboe 		return;
92414d0f45SJens Axboe 
93414d0f45SJens Axboe 	while ((entry = io_alloc_cache_get(cache)) != NULL)
94efba1a9eSBreno Leitao 		free(entry);
95414d0f45SJens Axboe 
96414d0f45SJens Axboe 	kvfree(cache->entries);
97414d0f45SJens Axboe 	cache->entries = NULL;
989b797a37SJens Axboe }
999b797a37SJens Axboe #endif
100