| /* SPDX-License-Identifier: GPL-2.0 */ | |
| #ifndef IOU_ALLOC_CACHE_H | |
| #define IOU_ALLOC_CACHE_H | |
| #include <linux/io_uring_types.h> | |
| #include <linux/kasan.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 bool io_alloc_cache_put(struct io_alloc_cache *cache, | |
| void *entry) | |
| { | |
| if (cache->nr_cached < cache->max_cached) { | |
| if (!kasan_mempool_poison_object(entry)) | |
| return false; | |
| cache->entries[cache->nr_cached++] = entry; | |
| return true; | |
| } | |
| return false; | |
| } | |
| 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 *obj; | |
| obj = io_alloc_cache_get(cache); | |
| if (obj) | |
| return obj; | |
| return io_cache_alloc_new(cache, gfp); | |
| } | |
| static inline void io_cache_free(struct io_alloc_cache *cache, void *obj) | |
| { | |
| if (!io_alloc_cache_put(cache, obj)) | |
| kvfree(obj); | |
| } | |
| #endif |