]>
exis.tech > repos - linux.git/blob - tools/testing/shared/linux.c
1 // SPDX-License-Identifier: GPL-2.0
10 #include <linux/poison.h>
11 #include <linux/slab.h>
12 #include <linux/radix-tree.h>
13 #include <urcu/uatomic.h>
19 void kmem_cache_set_callback(struct kmem_cache
*cachep
, void (*callback
)(void *))
21 cachep
->callback
= callback
;
24 void kmem_cache_set_private(struct kmem_cache
*cachep
, void *private)
26 cachep
->private = private;
29 void kmem_cache_set_non_kernel(struct kmem_cache
*cachep
, unsigned int val
)
31 cachep
->non_kernel
= val
;
34 unsigned long kmem_cache_get_alloc(struct kmem_cache
*cachep
)
36 return cachep
->size
* cachep
->nr_allocated
;
39 unsigned long kmem_cache_nr_allocated(struct kmem_cache
*cachep
)
41 return cachep
->nr_allocated
;
44 unsigned long kmem_cache_nr_tallocated(struct kmem_cache
*cachep
)
46 return cachep
->nr_tallocated
;
49 void kmem_cache_zero_nr_tallocated(struct kmem_cache
*cachep
)
51 cachep
->nr_tallocated
= 0;
54 void *kmem_cache_alloc_lru(struct kmem_cache
*cachep
, struct list_lru
*lru
,
59 if (cachep
->exec_callback
) {
61 cachep
->callback(cachep
->private);
62 cachep
->exec_callback
= false;
65 if (!(gfp
& __GFP_DIRECT_RECLAIM
)) {
66 if (!cachep
->non_kernel
) {
68 cachep
->exec_callback
= true;
75 pthread_mutex_lock(&cachep
->lock
);
76 if (cachep
->nr_objs
) {
77 struct radix_tree_node
*node
= cachep
->objs
;
79 cachep
->objs
= node
->parent
;
80 pthread_mutex_unlock(&cachep
->lock
);
84 pthread_mutex_unlock(&cachep
->lock
);
86 if (posix_memalign(&p
, cachep
->align
, cachep
->size
) < 0)
89 p
= malloc(cachep
->size
);
94 else if (gfp
& __GFP_ZERO
)
95 memset(p
, 0, cachep
->size
);
98 uatomic_inc(&cachep
->nr_allocated
);
99 uatomic_inc(&nr_allocated
);
100 uatomic_inc(&cachep
->nr_tallocated
);
102 printf("Allocating %p from slab\n", p
);
106 void __kmem_cache_free_locked(struct kmem_cache
*cachep
, void *objp
)
109 if (cachep
->nr_objs
> 10 || cachep
->align
) {
110 memset(objp
, POISON_FREE
, cachep
->size
);
113 struct radix_tree_node
*node
= objp
;
115 node
->parent
= cachep
->objs
;
120 void kmem_cache_free_locked(struct kmem_cache
*cachep
, void *objp
)
122 uatomic_dec(&nr_allocated
);
123 uatomic_dec(&cachep
->nr_allocated
);
125 printf("Freeing %p to slab\n", objp
);
126 __kmem_cache_free_locked(cachep
, objp
);
129 void kmem_cache_free(struct kmem_cache
*cachep
, void *objp
)
131 pthread_mutex_lock(&cachep
->lock
);
132 kmem_cache_free_locked(cachep
, objp
);
133 pthread_mutex_unlock(&cachep
->lock
);
136 void kmem_cache_free_bulk(struct kmem_cache
*cachep
, size_t size
, void **list
)
139 pr_debug("Bulk free %p[0-%zu]\n", list
, size
- 1);
141 if (cachep
->exec_callback
) {
142 if (cachep
->callback
)
143 cachep
->callback(cachep
->private);
144 cachep
->exec_callback
= false;
147 pthread_mutex_lock(&cachep
->lock
);
148 for (int i
= 0; i
< size
; i
++)
149 kmem_cache_free_locked(cachep
, list
[i
]);
150 pthread_mutex_unlock(&cachep
->lock
);
153 void kmem_cache_shrink(struct kmem_cache
*cachep
)
157 int kmem_cache_alloc_bulk(struct kmem_cache
*cachep
, gfp_t gfp
, size_t size
,
163 pr_debug("Bulk alloc %zu\n", size
);
165 pthread_mutex_lock(&cachep
->lock
);
166 if (cachep
->nr_objs
>= size
) {
167 struct radix_tree_node
*node
;
169 for (i
= 0; i
< size
; i
++) {
170 if (!(gfp
& __GFP_DIRECT_RECLAIM
)) {
171 if (!cachep
->non_kernel
)
173 cachep
->non_kernel
--;
178 cachep
->objs
= node
->parent
;
182 pthread_mutex_unlock(&cachep
->lock
);
184 pthread_mutex_unlock(&cachep
->lock
);
185 for (i
= 0; i
< size
; i
++) {
186 if (!(gfp
& __GFP_DIRECT_RECLAIM
)) {
187 if (!cachep
->non_kernel
)
189 cachep
->non_kernel
--;
193 if (posix_memalign(&p
[i
], cachep
->align
,
197 p
[i
] = malloc(cachep
->size
);
203 else if (gfp
& __GFP_ZERO
)
204 memset(p
[i
], 0, cachep
->size
);
210 pthread_mutex_lock(&cachep
->lock
);
211 for (i
= 0; i
< size
; i
++)
212 __kmem_cache_free_locked(cachep
, p
[i
]);
213 pthread_mutex_unlock(&cachep
->lock
);
214 if (cachep
->callback
)
215 cachep
->exec_callback
= true;
219 for (i
= 0; i
< size
; i
++) {
220 uatomic_inc(&nr_allocated
);
221 uatomic_inc(&cachep
->nr_allocated
);
222 uatomic_inc(&cachep
->nr_tallocated
);
224 printf("Allocating %p from slab\n", p
[i
]);
231 __kmem_cache_create_args(const char *name
, unsigned int size
,
232 struct kmem_cache_args
*args
,
235 struct kmem_cache
*ret
= malloc(sizeof(*ret
));
237 pthread_mutex_init(&ret
->lock
, NULL
);
239 ret
->align
= args
->align
;
240 ret
->sheaf_capacity
= args
->sheaf_capacity
;
242 ret
->nr_allocated
= 0;
243 ret
->nr_tallocated
= 0;
245 ret
->ctor
= args
->ctor
;
247 ret
->exec_callback
= false;
248 ret
->callback
= NULL
;
255 kmem_cache_prefill_sheaf(struct kmem_cache
*s
, gfp_t gfp
, unsigned int size
)
257 struct slab_sheaf
*sheaf
;
258 unsigned int capacity
;
260 if (s
->exec_callback
) {
262 s
->callback(s
->private);
263 s
->exec_callback
= false;
266 capacity
= max(size
, s
->sheaf_capacity
);
268 sheaf
= calloc(1, sizeof(*sheaf
) + sizeof(void *) * capacity
);
273 sheaf
->capacity
= capacity
;
274 sheaf
->size
= kmem_cache_alloc_bulk(s
, gfp
, size
, sheaf
->objects
);
283 int kmem_cache_refill_sheaf(struct kmem_cache
*s
, gfp_t gfp
,
284 struct slab_sheaf
**sheafp
, unsigned int size
)
286 struct slab_sheaf
*sheaf
= *sheafp
;
289 if (sheaf
->size
>= size
)
292 if (size
> sheaf
->capacity
) {
293 sheaf
= kmem_cache_prefill_sheaf(s
, gfp
, size
);
297 kmem_cache_return_sheaf(s
, gfp
, *sheafp
);
302 refill
= kmem_cache_alloc_bulk(s
, gfp
, size
- sheaf
->size
,
303 &sheaf
->objects
[sheaf
->size
]);
307 sheaf
->size
+= refill
;
311 void kmem_cache_return_sheaf(struct kmem_cache
*s
, gfp_t gfp
,
312 struct slab_sheaf
*sheaf
)
315 kmem_cache_free_bulk(s
, sheaf
->size
, &sheaf
->objects
[0]);
321 kmem_cache_alloc_from_sheaf(struct kmem_cache
*s
, gfp_t gfp
,
322 struct slab_sheaf
*sheaf
)
326 if (sheaf
->size
== 0) {
327 printf("Nothing left in sheaf!\n");
331 obj
= sheaf
->objects
[--sheaf
->size
];
332 sheaf
->objects
[sheaf
->size
] = NULL
;
338 * Test the test infrastructure for kem_cache_alloc/free and bulk counterparts.
340 void test_kmem_cache_bulk(void)
344 static struct kmem_cache
*test_cache
, *test_cache2
;
347 * Testing the bulk allocators without aligned kmem_cache to force the
348 * bulk alloc/free to reuse
350 test_cache
= kmem_cache_create("test_cache", 256, 0, SLAB_PANIC
, NULL
);
352 for (i
= 0; i
< 5; i
++)
353 list
[i
] = kmem_cache_alloc(test_cache
, __GFP_DIRECT_RECLAIM
);
355 for (i
= 0; i
< 5; i
++)
356 kmem_cache_free(test_cache
, list
[i
]);
357 assert(test_cache
->nr_objs
== 5);
359 kmem_cache_alloc_bulk(test_cache
, __GFP_DIRECT_RECLAIM
, 5, list
);
360 kmem_cache_free_bulk(test_cache
, 5, list
);
362 for (i
= 0; i
< 12 ; i
++)
363 list
[i
] = kmem_cache_alloc(test_cache
, __GFP_DIRECT_RECLAIM
);
365 for (i
= 0; i
< 12; i
++)
366 kmem_cache_free(test_cache
, list
[i
]);
368 /* The last free will not be kept around */
369 assert(test_cache
->nr_objs
== 11);
371 /* Aligned caches will immediately free */
372 test_cache2
= kmem_cache_create("test_cache2", 128, 128, SLAB_PANIC
, NULL
);
374 kmem_cache_alloc_bulk(test_cache2
, __GFP_DIRECT_RECLAIM
, 10, list
);
375 kmem_cache_free_bulk(test_cache2
, 10, list
);
376 assert(!test_cache2
->nr_objs
);