From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753892AbcLMU0R (ORCPT ); Tue, 13 Dec 2016 15:26:17 -0500 Received: from p3plsmtps2ded03.prod.phx3.secureserver.net ([208.109.80.60]:43040 "EHLO p3plsmtps2ded03.prod.phx3.secureserver.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752925AbcLMU0O (ORCPT ); Tue, 13 Dec 2016 15:26:14 -0500 x-originating-ip: 72.167.245.219 From: Matthew Wilcox To: linux-kernel@vger.kernel.org, Andrew Morton Cc: Matthew Wilcox , linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Konstantin Khlebnikov , Ross Zwisler , "Kirill A . Shutemov" , Tejun Heo Subject: [PATCH 1/5] radix tree test suite: Cache recently freed objects Date: Tue, 13 Dec 2016 14:21:28 -0800 Message-Id: <1481667692-14500-2-git-send-email-mawilcox@linuxonhyperv.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1481667692-14500-1-git-send-email-mawilcox@linuxonhyperv.com> References: <1481667692-14500-1-git-send-email-mawilcox@linuxonhyperv.com> X-CMAE-Envelope: MS4wfDWEW8apudIMMuPP0rADEhVLH0goLXGBEI2XC4v0h5o0l1hbO9vhlyPcMS+Jw6O34xoH46DN1E0iFCPxZlE5hq/WFSINsQ+lVhKnghxDsCi3zNknI/sF OC2jEvJxAJqW8RQGyzPEr0f4dLkD7FMamxPenzYu827qrSSALSzbWMqCsFRWOlwltiBtVeLFRJQ1/sy9FWsz04AtSk+inAb6ztSw7BVoOAdIR710LxZ5Dt/i o3mOe0f7SlCjPMPjpq7RhpVZuOeFpjVWPAFz4K5V8rBRkD+U9TM0KaXfU9/ArdNTQKfvhaCFMyTxumI09P0mS1QzeLjEEgbEtVxcEWKoVRf6RW79hXTi7XNh lY8cirU0MUS9xeFstBJgIbBpMSR48e9E3rRsduqC9mgAU237a6v0lG6p2b8JltjErKFCSPnh3Tw1TuR4fjoRaflwuYYXiDLgV7WlfFjOpMpO52pwP/OvlnqN C4UCyxd64riWtAF+ Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Matthew Wilcox 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). Signed-off-by: Matthew Wilcox --- tools/testing/radix-tree/linux.c | 48 ++++++++++++++++++++++++++++++----- tools/testing/radix-tree/linux/slab.h | 5 ---- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c index ff0452e..d31ea7c 100644 --- a/tools/testing/radix-tree/linux.c +++ b/tools/testing/radix-tree/linux.c @@ -1,16 +1,27 @@ #include #include #include +#include #include #include #include +#include #include +#include #include 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; } diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h index 446639f..e40337f 100644 --- a/tools/testing/radix-tree/linux/slab.h +++ b/tools/testing/radix-tree/linux/slab.h @@ -10,11 +10,6 @@ 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); -- 2.10.2