tools/testing: Add support for prefilled slab sheafs

Add the prefilled sheaf structs to the slab header and the associated
functions to the testing/shared/linux.c file.

Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
This commit is contained in:
Liam R. Howlett 2025-09-03 15:00:00 +02:00 committed by Vlastimil Babka
parent 025f93101b
commit fdbebab19f
2 changed files with 117 additions and 0 deletions

View file

@ -123,6 +123,18 @@ struct kmem_cache_args {
void (*ctor)(void *);
};
struct slab_sheaf {
union {
struct list_head barn_list;
/* only used for prefilled sheafs */
unsigned int capacity;
};
struct kmem_cache *cache;
unsigned int size;
int node; /* only used for rcu_sheaf */
void *objects[];
};
static inline void *kzalloc(size_t size, gfp_t gfp)
{
return kmalloc(size, gfp | __GFP_ZERO);
@ -173,5 +185,21 @@ __kmem_cache_create(const char *name, unsigned int size, unsigned int align,
void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list);
int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
void **list);
struct slab_sheaf *
kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size);
void *
kmem_cache_alloc_from_sheaf(struct kmem_cache *s, gfp_t gfp,
struct slab_sheaf *sheaf);
void kmem_cache_return_sheaf(struct kmem_cache *s, gfp_t gfp,
struct slab_sheaf *sheaf);
int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
struct slab_sheaf **sheafp, unsigned int size);
static inline unsigned int kmem_cache_sheaf_size(struct slab_sheaf *sheaf)
{
return sheaf->size;
}
#endif /* _TOOLS_SLAB_H */

View file

@ -137,6 +137,12 @@ void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list)
if (kmalloc_verbose)
pr_debug("Bulk free %p[0-%zu]\n", list, size - 1);
if (cachep->exec_callback) {
if (cachep->callback)
cachep->callback(cachep->private);
cachep->exec_callback = false;
}
pthread_mutex_lock(&cachep->lock);
for (int i = 0; i < size; i++)
kmem_cache_free_locked(cachep, list[i]);
@ -242,6 +248,89 @@ __kmem_cache_create_args(const char *name, unsigned int size,
return ret;
}
struct slab_sheaf *
kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size)
{
struct slab_sheaf *sheaf;
unsigned int capacity;
if (s->exec_callback) {
if (s->callback)
s->callback(s->private);
s->exec_callback = false;
}
capacity = max(size, s->sheaf_capacity);
sheaf = calloc(1, sizeof(*sheaf) + sizeof(void *) * capacity);
if (!sheaf)
return NULL;
sheaf->cache = s;
sheaf->capacity = capacity;
sheaf->size = kmem_cache_alloc_bulk(s, gfp, size, sheaf->objects);
if (!sheaf->size) {
free(sheaf);
return NULL;
}
return sheaf;
}
int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
struct slab_sheaf **sheafp, unsigned int size)
{
struct slab_sheaf *sheaf = *sheafp;
int refill;
if (sheaf->size >= size)
return 0;
if (size > sheaf->capacity) {
sheaf = kmem_cache_prefill_sheaf(s, gfp, size);
if (!sheaf)
return -ENOMEM;
kmem_cache_return_sheaf(s, gfp, *sheafp);
*sheafp = sheaf;
return 0;
}
refill = kmem_cache_alloc_bulk(s, gfp, size - sheaf->size,
&sheaf->objects[sheaf->size]);
if (!refill)
return -ENOMEM;
sheaf->size += refill;
return 0;
}
void kmem_cache_return_sheaf(struct kmem_cache *s, gfp_t gfp,
struct slab_sheaf *sheaf)
{
if (sheaf->size)
kmem_cache_free_bulk(s, sheaf->size, &sheaf->objects[0]);
free(sheaf);
}
void *
kmem_cache_alloc_from_sheaf(struct kmem_cache *s, gfp_t gfp,
struct slab_sheaf *sheaf)
{
void *obj;
if (sheaf->size == 0) {
printf("Nothing left in sheaf!\n");
return NULL;
}
obj = sheaf->objects[--sheaf->size];
sheaf->objects[sheaf->size] = NULL;
return obj;
}
/*
* Test the test infrastructure for kem_cache_alloc/free and bulk counterparts.
*/