Commit fdbebab1 authored by Liam R. Howlett's avatar Liam R. Howlett Committed by Vlastimil Babka
Browse files

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: default avatarLiam R. Howlett <Liam.Howlett@oracle.com>
Reviewed-by: default avatarSuren Baghdasaryan <surenb@google.com>
Signed-off-by: default avatarVlastimil Babka <vbabka@suse.cz>
parent 025f9310
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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 */
+89 −0
Original line number Diff line number Diff line
@@ -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.
 */