radix tree test suite: cache recently freed objects
authorMatthew Wilcox <mawilcox@microsoft.com>
Wed, 14 Dec 2016 23:09:28 +0000 (15:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2016 00:04:10 +0000 (16:04 -0800)
The kmem_cache_alloc implementation simply allocates new memory from
malloc() and calls the ctor, which zeroes out the entire object.  This
means it cannot spot bugs where the object isn't properly reinitialised
before being freed.

Add a small (11 objects) cache before freeing objects back to malloc.
This is enough to let us write a test to catch it, although the memory
allocator is now aware of the structure of the radix tree node, since it
chains free objects through ->private_data (like the percpu cache does).

Link: http://lkml.kernel.org/r/1481667692-14500-2-git-send-email-mawilcox@linuxonhyperv.com
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
tools/testing/radix-tree/linux.c
tools/testing/radix-tree/linux/slab.h

index ff0452e8a0c4522181344cb9d2eb2c56105d481e..d31ea7c9abec8231b37e6e61efbd56e7e7f09706 100644 (file)
@@ -1,16 +1,27 @@
 #include <stdlib.h>
 #include <string.h>
 #include <malloc.h>
+#include <pthread.h>
 #include <unistd.h>
 #include <assert.h>
 
 #include <linux/mempool.h>
+#include <linux/poison.h>
 #include <linux/slab.h>
+#include <linux/radix-tree.h>
 #include <urcu/uatomic.h>
 
 int nr_allocated;
 int preempt_count;
 
+struct kmem_cache {
+       pthread_mutex_t lock;
+       int size;
+       int nr_objs;
+       void *objs;
+       void (*ctor)(void *);
+};
+
 void *mempool_alloc(mempool_t *pool, int gfp_mask)
 {
        return pool->alloc(gfp_mask, pool->data);
@@ -34,24 +45,44 @@ mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
 
 void *kmem_cache_alloc(struct kmem_cache *cachep, int flags)
 {
-       void *ret;
+       struct radix_tree_node *node;
 
        if (flags & __GFP_NOWARN)
                return NULL;
 
-       ret = malloc(cachep->size);
-       if (cachep->ctor)
-               cachep->ctor(ret);
+       pthread_mutex_lock(&cachep->lock);
+       if (cachep->nr_objs) {
+               cachep->nr_objs--;
+               node = cachep->objs;
+               cachep->objs = node->private_data;
+               pthread_mutex_unlock(&cachep->lock);
+               node->private_data = NULL;
+       } else {
+               pthread_mutex_unlock(&cachep->lock);
+               node = malloc(cachep->size);
+               if (cachep->ctor)
+                       cachep->ctor(node);
+       }
+
        uatomic_inc(&nr_allocated);
-       return ret;
+       return node;
 }
 
 void kmem_cache_free(struct kmem_cache *cachep, void *objp)
 {
        assert(objp);
        uatomic_dec(&nr_allocated);
-       memset(objp, 0, cachep->size);
-       free(objp);
+       pthread_mutex_lock(&cachep->lock);
+       if (cachep->nr_objs > 10) {
+               memset(objp, POISON_FREE, cachep->size);
+               free(objp);
+       } else {
+               struct radix_tree_node *node = objp;
+               cachep->nr_objs++;
+               node->private_data = cachep->objs;
+               cachep->objs = node;
+       }
+       pthread_mutex_unlock(&cachep->lock);
 }
 
 void *kmalloc(size_t size, gfp_t gfp)
@@ -75,7 +106,10 @@ kmem_cache_create(const char *name, size_t size, size_t offset,
 {
        struct kmem_cache *ret = malloc(sizeof(*ret));
 
+       pthread_mutex_init(&ret->lock, NULL);
        ret->size = size;
+       ret->nr_objs = 0;
+       ret->objs = NULL;
        ret->ctor = ctor;
        return ret;
 }
index 446639f78fc1c508a7a1d6f016578028b0bdc870..e40337f41a387a40eec30af0c4f43fb18ae8b1fe 100644 (file)
 void *kmalloc(size_t size, gfp_t);
 void kfree(void *);
 
-struct kmem_cache {
-       int size;
-       void (*ctor)(void *);
-};
-
 void *kmem_cache_alloc(struct kmem_cache *cachep, int flags);
 void kmem_cache_free(struct kmem_cache *cachep, void *objp);