[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAJuCfpGOwZY=MSizk-xx9R4cBBP0MgYA0MQhAv9Svf0Yt1DgjQ@mail.gmail.com>
Date: Sat, 22 Feb 2025 20:24:46 -0800
From: Suren Baghdasaryan <surenb@...gle.com>
To: Vlastimil Babka <vbabka@...e.cz>
Cc: "Liam R. Howlett" <Liam.Howlett@...cle.com>, Christoph Lameter <cl@...ux.com>,
David Rientjes <rientjes@...gle.com>, Roman Gushchin <roman.gushchin@...ux.dev>,
Hyeonggon Yoo <42.hyeyoo@...il.com>, Uladzislau Rezki <urezki@...il.com>, linux-mm@...ck.org,
linux-kernel@...r.kernel.org, rcu@...r.kernel.org,
maple-tree@...ts.infradead.org
Subject: Re: [PATCH RFC v2 08/10] tools: Add testing support for changes to
rcu and slab for sheaves
On Fri, Feb 14, 2025 at 8:27 AM Vlastimil Babka <vbabka@...e.cz> wrote:
>
> From: "Liam R. Howlett" <Liam.Howlett@...cle.com>
>
> Make testing work for the slab and rcu changes that have come in with
> the sheaves work.
>
> This only works with one kmem_cache, and only the first one used.
> Subsequent setting of keme_cache will not update the active kmem_cache
s/keme_cache/kmem_cache
> and will be silently dropped because there are other tests which happen
> after the kmem_cache of interest is set.
>
> The saved active kmem_cache is used in the rcu callback, which passes
> the object to be freed.
>
> The rcu call takes the rcu_head, which is passed in as the field in the
> struct (in this case rcu in the maple tree node), which is calculated by
> pointer math. The offset of which is saved (in a global variable) for
> restoring the node pointer on the callback after the rcu grace period
> expires.
>
> Don't use any of this outside of testing, please.
>
> Signed-off-by: Liam R. Howlett <Liam.Howlett@...cle.com>
> ---
> tools/include/linux/slab.h | 41 ++++++++++++++++++++++++++++++++---
> tools/testing/shared/linux.c | 24 ++++++++++++++++----
> tools/testing/shared/linux/rcupdate.h | 22 +++++++++++++++++++
> 3 files changed, 80 insertions(+), 7 deletions(-)
>
> diff --git a/tools/include/linux/slab.h b/tools/include/linux/slab.h
> index 51b25e9c4ec7b66bdf4c68cc1353c6faf1ca7bb8..a475364cfd9fcdb10db252aab18ea3a620326b6b 100644
> --- a/tools/include/linux/slab.h
> +++ b/tools/include/linux/slab.h
> @@ -22,6 +22,12 @@ enum slab_state {
> FULL
> };
>
> +struct kmem_cache_args {
> + unsigned int align;
> + unsigned int sheaf_capacity;
> + void (*ctor)(void *);
> +};
> +
> static inline void *kzalloc(size_t size, gfp_t gfp)
> {
> return kmalloc(size, gfp | __GFP_ZERO);
> @@ -36,9 +42,38 @@ static inline void *kmem_cache_alloc(struct kmem_cache *cachep, int flags)
> }
> void kmem_cache_free(struct kmem_cache *cachep, void *objp);
>
> -struct kmem_cache *kmem_cache_create(const char *name, unsigned int size,
> - unsigned int align, unsigned int flags,
> - void (*ctor)(void *));
> +
> +struct kmem_cache *
> +__kmem_cache_create_args(const char *name, unsigned int size,
> + struct kmem_cache_args *args, unsigned int flags);
> +
> +/* If NULL is passed for @args, use this variant with default arguments. */
> +static inline struct kmem_cache *
> +__kmem_cache_default_args(const char *name, unsigned int size,
> + struct kmem_cache_args *args, unsigned int flags)
> +{
> + struct kmem_cache_args kmem_default_args = {};
> +
> + return __kmem_cache_create_args(name, size, &kmem_default_args, flags);
> +}
> +
> +static inline struct kmem_cache *
> +__kmem_cache_create(const char *name, unsigned int size, unsigned int align,
> + unsigned int flags, void (*ctor)(void *))
> +{
> + struct kmem_cache_args kmem_args = {
> + .align = align,
> + .ctor = ctor,
> + };
> +
> + return __kmem_cache_create_args(name, size, &kmem_args, flags);
> +}
> +
> +#define kmem_cache_create(__name, __object_size, __args, ...) \
> + _Generic((__args), \
> + struct kmem_cache_args *: __kmem_cache_create_args, \
> + void *: __kmem_cache_default_args, \
> + default: __kmem_cache_create)(__name, __object_size, __args, __VA_ARGS__)
>
> 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,
> diff --git a/tools/testing/shared/linux.c b/tools/testing/shared/linux.c
> index 66dbb362385f3c3d923233448cc591adfe6dc9e7..9f5fd722f27f1d3877be8927be30409cd74ab3c3 100644
> --- a/tools/testing/shared/linux.c
> +++ b/tools/testing/shared/linux.c
> @@ -20,6 +20,7 @@ struct kmem_cache {
> pthread_mutex_t lock;
> unsigned int size;
> unsigned int align;
> + unsigned int sheaf_capacity;
> int nr_objs;
> void *objs;
> void (*ctor)(void *);
> @@ -31,6 +32,8 @@ struct kmem_cache {
> void *private;
> };
>
> +static struct kmem_cache *kmem_active = NULL;
> +
> void kmem_cache_set_callback(struct kmem_cache *cachep, void (*callback)(void *))
> {
> cachep->callback = callback;
> @@ -147,6 +150,14 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp)
> pthread_mutex_unlock(&cachep->lock);
> }
>
> +void kmem_cache_free_active(void *objp)
> +{
> + if (!kmem_active)
> + printf("WARNING: No active kmem_cache\n");
> +
> + kmem_cache_free(kmem_active, objp);
> +}
> +
> void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list)
> {
> if (kmalloc_verbose)
> @@ -234,23 +245,28 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
> }
>
> struct kmem_cache *
> -kmem_cache_create(const char *name, unsigned int size, unsigned int align,
> - unsigned int flags, void (*ctor)(void *))
> +__kmem_cache_create_args(const char *name, unsigned int size,
> + struct kmem_cache_args *args,
> + unsigned int flags)
> {
> struct kmem_cache *ret = malloc(sizeof(*ret));
>
> pthread_mutex_init(&ret->lock, NULL);
> ret->size = size;
> - ret->align = align;
> + ret->align = args->align;
> + ret->sheaf_capacity = args->sheaf_capacity;
> ret->nr_objs = 0;
> ret->nr_allocated = 0;
> ret->nr_tallocated = 0;
> ret->objs = NULL;
> - ret->ctor = ctor;
> + ret->ctor = args->ctor;
> ret->non_kernel = 0;
> ret->exec_callback = false;
> ret->callback = NULL;
> ret->private = NULL;
> + if (!kmem_active)
> + kmem_active = ret;
This kmem_active and kfree_cb_offset look like bad hacks... Could we
maybe modify kmem_cache_alloc() to allocate a small metadata at the
beginning to store a pointer to kmem_cache and kfree_cb_offset value?
> +
> return ret;
> }
>
> diff --git a/tools/testing/shared/linux/rcupdate.h b/tools/testing/shared/linux/rcupdate.h
> index fed468fb0c78db6f33fb1900c7110ab5f3c19c65..c95e2f0bbd93798e544d7d34e0823ed68414f924 100644
> --- a/tools/testing/shared/linux/rcupdate.h
> +++ b/tools/testing/shared/linux/rcupdate.h
> @@ -9,4 +9,26 @@
> #define rcu_dereference_check(p, cond) rcu_dereference(p)
> #define RCU_INIT_POINTER(p, v) do { (p) = (v); } while (0)
>
> +void kmem_cache_free_active(void *objp);
> +static unsigned long kfree_cb_offset = 0;
> +
> +static inline void kfree_rcu_cb(struct rcu_head *head)
> +{
> + void *objp = (void *) ((unsigned long)head - kfree_cb_offset);
> +
> + kmem_cache_free_active(objp);
> +}
> +
> +#ifndef offsetof
> +#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
> +#endif
> +
> +#define kfree_rcu(ptr, rhv) \
> +do { \
> + if (!kfree_cb_offset) \
> + kfree_cb_offset = offsetof(typeof(*(ptr)), rhv); \
> + \
> + call_rcu(&ptr->rhv, kfree_rcu_cb); \
> +} while (0)
> +
> #endif
>
> --
> 2.48.1
>
Powered by blists - more mailing lists