1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdlib.h> 3 #include <string.h> 4 #include <malloc.h> 5 #include <pthread.h> 6 #include <unistd.h> 7 #include <assert.h> 8 9 #include <linux/gfp.h> 10 #include <linux/poison.h> 11 #include <linux/slab.h> 12 #include <linux/radix-tree.h> 13 #include <urcu/uatomic.h> 14 15 int nr_allocated; 16 int preempt_count; 17 int kmalloc_verbose; 18 int test_verbose; 19 20 struct kmem_cache { 21 pthread_mutex_t lock; 22 unsigned int size; 23 unsigned int align; 24 int nr_objs; 25 void *objs; 26 void (*ctor)(void *); 27 }; 28 29 void *kmem_cache_alloc(struct kmem_cache *cachep, int gfp) 30 { 31 void *p; 32 33 if (!(gfp & __GFP_DIRECT_RECLAIM)) 34 return NULL; 35 36 pthread_mutex_lock(&cachep->lock); 37 if (cachep->nr_objs) { 38 struct radix_tree_node *node = cachep->objs; 39 cachep->nr_objs--; 40 cachep->objs = node->parent; 41 pthread_mutex_unlock(&cachep->lock); 42 node->parent = NULL; 43 p = node; 44 } else { 45 pthread_mutex_unlock(&cachep->lock); 46 if (cachep->align) 47 posix_memalign(&p, cachep->align, cachep->size); 48 else 49 p = malloc(cachep->size); 50 if (cachep->ctor) 51 cachep->ctor(p); 52 else if (gfp & __GFP_ZERO) 53 memset(p, 0, cachep->size); 54 } 55 56 uatomic_inc(&nr_allocated); 57 if (kmalloc_verbose) 58 printf("Allocating %p from slab\n", p); 59 return p; 60 } 61 62 void kmem_cache_free(struct kmem_cache *cachep, void *objp) 63 { 64 assert(objp); 65 uatomic_dec(&nr_allocated); 66 if (kmalloc_verbose) 67 printf("Freeing %p to slab\n", objp); 68 pthread_mutex_lock(&cachep->lock); 69 if (cachep->nr_objs > 10 || cachep->align) { 70 memset(objp, POISON_FREE, cachep->size); 71 free(objp); 72 } else { 73 struct radix_tree_node *node = objp; 74 cachep->nr_objs++; 75 node->parent = cachep->objs; 76 cachep->objs = node; 77 } 78 pthread_mutex_unlock(&cachep->lock); 79 } 80 81 void *kmalloc(size_t size, gfp_t gfp) 82 { 83 void *ret; 84 85 if (!(gfp & __GFP_DIRECT_RECLAIM)) 86 return NULL; 87 88 ret = malloc(size); 89 uatomic_inc(&nr_allocated); 90 if (kmalloc_verbose) 91 printf("Allocating %p from malloc\n", ret); 92 if (gfp & __GFP_ZERO) 93 memset(ret, 0, size); 94 return ret; 95 } 96 97 void kfree(void *p) 98 { 99 if (!p) 100 return; 101 uatomic_dec(&nr_allocated); 102 if (kmalloc_verbose) 103 printf("Freeing %p to malloc\n", p); 104 free(p); 105 } 106 107 struct kmem_cache * 108 kmem_cache_create(const char *name, unsigned int size, unsigned int align, 109 unsigned int flags, void (*ctor)(void *)) 110 { 111 struct kmem_cache *ret = malloc(sizeof(*ret)); 112 113 pthread_mutex_init(&ret->lock, NULL); 114 ret->size = size; 115 ret->align = align; 116 ret->nr_objs = 0; 117 ret->objs = NULL; 118 ret->ctor = ctor; 119 return ret; 120 } 121