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