linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB
@ 2014-05-07  6:06 Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 01/10] slab: add unlikely macro to help compiler Joonsoo Kim
                   ` (10 more replies)
  0 siblings, 11 replies; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

This patchset does some clean-up and tries to remove lockdep annotation.

Patches 1~3 are just for really really minor improvement.
Patches 4~10 are for clean-up and removing lockdep annotation.

There are two cases that lockdep annotation is needed in SLAB.
1) holding two node locks
2) holding two array cache(alien cache) locks

I looked at the code and found that we can avoid these cases without
any negative effect.

1) occurs if freeing object makes new free slab and we decide to
destroy it. Although we don't need to hold the lock during destroying
a slab, current code do that. Destroying a slab without holding the lock
would help the reduction of the lock contention. To do it, I change the
implementation that new free slab is destroyed after releasing the lock.

2) occurs on similar situation. When we free object from non-local node,
we put this object to alien cache with holding the alien cache lock.
If alien cache is full, we try to flush alien cache to proper node cache,
and, in this time, new free slab could be made. Destroying it would be
started and we will free metadata object which comes from another node.
In this case, we need another node's alien cache lock to free object.
This forces us to hold two array cache locks and then we need lockdep
annotation although they are always different locks and deadlock cannot
be possible. To prevent this situation, I use same way as 1).

In this way, we can avoid 1) and 2) cases, and then, can remove lockdep
annotation. As short stat noted, this makes SLAB code much simpler.

Many of this series get Ack from Christoph Lameter on previous iteration,
but 1, 2, 9 and 10 need to get Ack. There is no big change from previous
iteration. It is just rebased on current linux-next.

Thanks.

Joonsoo Kim (10):
  slab: add unlikely macro to help compiler
  slab: makes clear_obj_pfmemalloc() just return masked value
  slab: move up code to get kmem_cache_node in free_block()
  slab: defer slab_destroy in free_block()
  slab: factor out initialization of arracy cache
  slab: introduce alien_cache
  slab: use the lock on alien_cache, instead of the lock on array_cache
  slab: destroy a slab without holding any alien cache lock
  slab: remove a useless lockdep annotation
  slab: remove BAD_ALIEN_MAGIC

 mm/slab.c |  391 ++++++++++++++++++++++---------------------------------------
 mm/slab.h |    2 +-
 2 files changed, 140 insertions(+), 253 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 01/10] slab: add unlikely macro to help compiler
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07 14:21   ` Christoph Lameter
  2014-05-07  6:06 ` [PATCH v2 02/10] slab: makes clear_obj_pfmemalloc() just return masked value Joonsoo Kim
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

slab_should_failslab() is called on every allocation, so to optimize it
is reasonable. We normally don't allocate from kmem_cache. It is just
used when new kmem_cache is created, so it's very rare case. Therefore,
add unlikely macro to help compiler optimization.

Acked-by: David Rientjes <rientjes@google.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 25317fd..1fede40 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2993,7 +2993,7 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
 
 static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags)
 {
-	if (cachep == kmem_cache)
+	if (unlikely(cachep == kmem_cache))
 		return false;
 
 	return should_failslab(cachep->object_size, flags, cachep->flags);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 02/10] slab: makes clear_obj_pfmemalloc() just return masked value
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 01/10] slab: add unlikely macro to help compiler Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07 14:22   ` Christoph Lameter
  2014-05-07  6:06 ` [PATCH v2 03/10] slab: move up code to get kmem_cache_node in free_block() Joonsoo Kim
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

clear_obj_pfmemalloc() takes the pointer to pointer to store masked value
back into this address. But this is useless, since we don't use this stored
value anymore. All we need is just masked value so makes clear_obj_pfmemalloc()
just return masked value.

v2: simplify commit description.
    directly return return value of clear_obj_pfmemalloc().

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 1fede40..e2c80df 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -215,9 +215,9 @@ static inline void set_obj_pfmemalloc(void **objp)
 	return;
 }
 
-static inline void clear_obj_pfmemalloc(void **objp)
+static inline void *clear_obj_pfmemalloc(void *objp)
 {
-	*objp = (void *)((unsigned long)*objp & ~SLAB_OBJ_PFMEMALLOC);
+	return (void *)((unsigned long)objp & ~SLAB_OBJ_PFMEMALLOC);
 }
 
 /*
@@ -809,10 +809,8 @@ static void *__ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,
 	if (unlikely(is_obj_pfmemalloc(objp))) {
 		struct kmem_cache_node *n;
 
-		if (gfp_pfmemalloc_allowed(flags)) {
-			clear_obj_pfmemalloc(&objp);
-			return objp;
-		}
+		if (gfp_pfmemalloc_allowed(flags))
+			return clear_obj_pfmemalloc(objp);
 
 		/* The caller cannot use PFMEMALLOC objects, find another one */
 		for (i = 0; i < ac->avail; i++) {
@@ -833,9 +831,8 @@ static void *__ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,
 		if (!list_empty(&n->slabs_free) && force_refill) {
 			struct page *page = virt_to_head_page(objp);
 			ClearPageSlabPfmemalloc(page);
-			clear_obj_pfmemalloc(&objp);
 			recheck_pfmemalloc_active(cachep, ac);
-			return objp;
+			return clear_obj_pfmemalloc(objp);
 		}
 
 		/* No !PFMEMALLOC objects available */
@@ -3349,8 +3346,7 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
 		void *objp;
 		struct page *page;
 
-		clear_obj_pfmemalloc(&objpp[i]);
-		objp = objpp[i];
+		objp = clear_obj_pfmemalloc(objpp[i]);
 
 		page = virt_to_head_page(objp);
 		n = cachep->node[node];
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 03/10] slab: move up code to get kmem_cache_node in free_block()
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 01/10] slab: add unlikely macro to help compiler Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 02/10] slab: makes clear_obj_pfmemalloc() just return masked value Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-08  0:52   ` David Rientjes
  2014-05-07  6:06 ` [PATCH v2 04/10] slab: defer slab_destroy " Joonsoo Kim
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

node isn't changed, so we don't need to retreive this structure
everytime we move the object. Maybe compiler do this optimization,
but making it explicitly is better.

Acked-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index e2c80df..92d08e3 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3340,7 +3340,7 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
 		       int node)
 {
 	int i;
-	struct kmem_cache_node *n;
+	struct kmem_cache_node *n = cachep->node[node];
 
 	for (i = 0; i < nr_objects; i++) {
 		void *objp;
@@ -3349,7 +3349,6 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
 		objp = clear_obj_pfmemalloc(objpp[i]);
 
 		page = virt_to_head_page(objp);
-		n = cachep->node[node];
 		list_del(&page->lru);
 		check_spinlock_acquired_node(cachep, node);
 		slab_put_obj(cachep, page, objp, node);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 04/10] slab: defer slab_destroy in free_block()
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (2 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 03/10] slab: move up code to get kmem_cache_node in free_block() Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-08  1:01   ` David Rientjes
  2014-05-07  6:06 ` [PATCH v2 05/10] slab: factor out initialization of arracy cache Joonsoo Kim
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

In free_block(), if freeing object makes new free slab and number of
free_objects exceeds free_limit, we start to destroy this new free slab
with holding the kmem_cache node lock. Holding the lock is useless and,
generally, holding a lock as least as possible is good thing. I never
measure performance effect of this, but we'd be better not to hold the lock
as much as possible.

Commented by Christoph:
  This is also good because kmem_cache_free is no longer called while
  holding the node lock. So we avoid one case of recursion.

Acked-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 92d08e3..7647728 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -242,7 +242,8 @@ static struct kmem_cache_node __initdata init_kmem_cache_node[NUM_INIT_LISTS];
 static int drain_freelist(struct kmem_cache *cache,
 			struct kmem_cache_node *n, int tofree);
 static void free_block(struct kmem_cache *cachep, void **objpp, int len,
-			int node);
+			int node, struct list_head *list);
+static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list);
 static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp);
 static void cache_reap(struct work_struct *unused);
 
@@ -976,6 +977,7 @@ static void free_alien_cache(struct array_cache **ac_ptr)
 static void __drain_alien_cache(struct kmem_cache *cachep,
 				struct array_cache *ac, int node)
 {
+	LIST_HEAD(list);
 	struct kmem_cache_node *n = cachep->node[node];
 
 	if (ac->avail) {
@@ -988,9 +990,10 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
 		if (n->shared)
 			transfer_objects(n->shared, ac, ac->limit);
 
-		free_block(cachep, ac->entry, ac->avail, node);
+		free_block(cachep, ac->entry, ac->avail, node, &list);
 		ac->avail = 0;
 		spin_unlock(&n->list_lock);
+		slabs_destroy(cachep, &list);
 	}
 }
 
@@ -1034,6 +1037,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 	struct kmem_cache_node *n;
 	struct array_cache *alien = NULL;
 	int node;
+	LIST_HEAD(list);
 
 	node = numa_mem_id();
 
@@ -1057,8 +1061,9 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 		spin_unlock(&alien->lock);
 	} else {
 		spin_lock(&(cachep->node[nodeid])->list_lock);
-		free_block(cachep, &objp, 1, nodeid);
+		free_block(cachep, &objp, 1, nodeid, &list);
 		spin_unlock(&(cachep->node[nodeid])->list_lock);
+		slabs_destroy(cachep, &list);
 	}
 	return 1;
 }
@@ -1127,6 +1132,7 @@ static void cpuup_canceled(long cpu)
 		struct array_cache *nc;
 		struct array_cache *shared;
 		struct array_cache **alien;
+		LIST_HEAD(list);
 
 		/* cpu is dead; no one can alloc from it. */
 		nc = cachep->array[cpu];
@@ -1141,7 +1147,7 @@ static void cpuup_canceled(long cpu)
 		/* Free limit for this kmem_cache_node */
 		n->free_limit -= cachep->batchcount;
 		if (nc)
-			free_block(cachep, nc->entry, nc->avail, node);
+			free_block(cachep, nc->entry, nc->avail, node, &list);
 
 		if (!cpumask_empty(mask)) {
 			spin_unlock_irq(&n->list_lock);
@@ -1151,7 +1157,7 @@ static void cpuup_canceled(long cpu)
 		shared = n->shared;
 		if (shared) {
 			free_block(cachep, shared->entry,
-				   shared->avail, node);
+				   shared->avail, node, &list);
 			n->shared = NULL;
 		}
 
@@ -1159,6 +1165,7 @@ static void cpuup_canceled(long cpu)
 		n->alien = NULL;
 
 		spin_unlock_irq(&n->list_lock);
+		slabs_destroy(cachep, &list);
 
 		kfree(shared);
 		if (alien) {
@@ -1999,6 +2006,15 @@ static void slab_destroy(struct kmem_cache *cachep, struct page *page)
 		kmem_cache_free(cachep->freelist_cache, freelist);
 }
 
+static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
+{
+	struct page *page, *n;
+	list_for_each_entry_safe(page, n, list, lru) {
+		list_del(&page->lru);
+		slab_destroy(cachep, page);
+	}
+}
+
 /**
  * calculate_slab_order - calculate size (page order) of slabs
  * @cachep: pointer to the cache that is being created
@@ -2399,12 +2415,14 @@ static void do_drain(void *arg)
 	struct kmem_cache *cachep = arg;
 	struct array_cache *ac;
 	int node = numa_mem_id();
+	LIST_HEAD(list);
 
 	check_irq_off();
 	ac = cpu_cache_get(cachep);
 	spin_lock(&cachep->node[node]->list_lock);
-	free_block(cachep, ac->entry, ac->avail, node);
+	free_block(cachep, ac->entry, ac->avail, node, &list);
 	spin_unlock(&cachep->node[node]->list_lock);
+	slabs_destroy(cachep, &list);
 	ac->avail = 0;
 }
 
@@ -3336,8 +3354,8 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller)
 /*
  * Caller needs to acquire correct kmem_cache_node's list_lock
  */
-static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
-		       int node)
+static void free_block(struct kmem_cache *cachep, void **objpp,
+			int nr_objects, int node, struct list_head *list)
 {
 	int i;
 	struct kmem_cache_node *n = cachep->node[node];
@@ -3359,13 +3377,7 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
 		if (page->active == 0) {
 			if (n->free_objects > n->free_limit) {
 				n->free_objects -= cachep->num;
-				/* No need to drop any previously held
-				 * lock here, even if we have a off-slab slab
-				 * descriptor it is guaranteed to come from
-				 * a different cache, refer to comments before
-				 * alloc_slabmgmt.
-				 */
-				slab_destroy(cachep, page);
+				list_add(&page->lru, list);
 			} else {
 				list_add(&page->lru, &n->slabs_free);
 			}
@@ -3384,6 +3396,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
 	int batchcount;
 	struct kmem_cache_node *n;
 	int node = numa_mem_id();
+	LIST_HEAD(list);
 
 	batchcount = ac->batchcount;
 #if DEBUG
@@ -3405,7 +3418,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
 		}
 	}
 
-	free_block(cachep, ac->entry, batchcount, node);
+	free_block(cachep, ac->entry, batchcount, node, &list);
 free_done:
 #if STATS
 	{
@@ -3426,6 +3439,7 @@ free_done:
 	}
 #endif
 	spin_unlock(&n->list_lock);
+	slabs_destroy(cachep, &list);
 	ac->avail -= batchcount;
 	memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail);
 }
@@ -3706,12 +3720,13 @@ static int alloc_kmem_cache_node(struct kmem_cache *cachep, gfp_t gfp)
 		n = cachep->node[node];
 		if (n) {
 			struct array_cache *shared = n->shared;
+			LIST_HEAD(list);
 
 			spin_lock_irq(&n->list_lock);
 
 			if (shared)
 				free_block(cachep, shared->entry,
-						shared->avail, node);
+						shared->avail, node, &list);
 
 			n->shared = new_shared;
 			if (!n->alien) {
@@ -3721,6 +3736,7 @@ static int alloc_kmem_cache_node(struct kmem_cache *cachep, gfp_t gfp)
 			n->free_limit = (1 + nr_cpus_node(node)) *
 					cachep->batchcount + cachep->num;
 			spin_unlock_irq(&n->list_lock);
+			slabs_destroy(cachep, &list);
 			kfree(shared);
 			free_alien_cache(new_alien);
 			continue;
@@ -3811,12 +3827,15 @@ static int __do_tune_cpucache(struct kmem_cache *cachep, int limit,
 	cachep->shared = shared;
 
 	for_each_online_cpu(i) {
+		LIST_HEAD(list);
 		struct array_cache *ccold = new->new[i];
 		if (!ccold)
 			continue;
 		spin_lock_irq(&cachep->node[cpu_to_mem(i)]->list_lock);
-		free_block(cachep, ccold->entry, ccold->avail, cpu_to_mem(i));
+		free_block(cachep, ccold->entry, ccold->avail,
+						cpu_to_mem(i), &list);
 		spin_unlock_irq(&cachep->node[cpu_to_mem(i)]->list_lock);
+		slabs_destroy(cachep, &list);
 		kfree(ccold);
 	}
 	kfree(new);
@@ -3924,6 +3943,7 @@ skip_setup:
 static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n,
 			 struct array_cache *ac, int force, int node)
 {
+	LIST_HEAD(list);
 	int tofree;
 
 	if (!ac || !ac->avail)
@@ -3936,12 +3956,13 @@ static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n,
 			tofree = force ? ac->avail : (ac->limit + 4) / 5;
 			if (tofree > ac->avail)
 				tofree = (ac->avail + 1) / 2;
-			free_block(cachep, ac->entry, tofree, node);
+			free_block(cachep, ac->entry, tofree, node, &list);
 			ac->avail -= tofree;
 			memmove(ac->entry, &(ac->entry[tofree]),
 				sizeof(void *) * ac->avail);
 		}
 		spin_unlock_irq(&n->list_lock);
+		slabs_destroy(cachep, &list);
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 05/10] slab: factor out initialization of arracy cache
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (3 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 04/10] slab: defer slab_destroy " Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-08  1:19   ` David Rientjes
  2014-05-07  6:06 ` [PATCH v2 06/10] slab: introduce alien_cache Joonsoo Kim
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

Factor out initialization of array cache to use it in following patch.

Acked-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 7647728..755fb57 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -741,13 +741,8 @@ static void start_cpu_timer(int cpu)
 	}
 }
 
-static struct array_cache *alloc_arraycache(int node, int entries,
-					    int batchcount, gfp_t gfp)
+static void init_arraycache(struct array_cache *ac, int limit, int batch)
 {
-	int memsize = sizeof(void *) * entries + sizeof(struct array_cache);
-	struct array_cache *nc = NULL;
-
-	nc = kmalloc_node(memsize, gfp, node);
 	/*
 	 * The array_cache structures contain pointers to free object.
 	 * However, when such objects are allocated or transferred to another
@@ -755,15 +750,25 @@ static struct array_cache *alloc_arraycache(int node, int entries,
 	 * valid references during a kmemleak scan. Therefore, kmemleak must
 	 * not scan such objects.
 	 */
-	kmemleak_no_scan(nc);
-	if (nc) {
-		nc->avail = 0;
-		nc->limit = entries;
-		nc->batchcount = batchcount;
-		nc->touched = 0;
-		spin_lock_init(&nc->lock);
+	kmemleak_no_scan(ac);
+	if (ac) {
+		ac->avail = 0;
+		ac->limit = limit;
+		ac->batchcount = batch;
+		ac->touched = 0;
+		spin_lock_init(&ac->lock);
 	}
-	return nc;
+}
+
+static struct array_cache *alloc_arraycache(int node, int entries,
+					    int batchcount, gfp_t gfp)
+{
+	int memsize = sizeof(void *) * entries + sizeof(struct array_cache);
+	struct array_cache *ac = NULL;
+
+	ac = kmalloc_node(memsize, gfp, node);
+	init_arraycache(ac, entries, batchcount);
+	return ac;
 }
 
 static inline bool is_slab_pfmemalloc(struct page *page)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 06/10] slab: introduce alien_cache
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (4 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 05/10] slab: factor out initialization of arracy cache Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 07/10] slab: use the lock on alien_cache, instead of the lock on array_cache Joonsoo Kim
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

Currently, we use array_cache for alien_cache. Although they are mostly
similar, there is one difference, that is, need for spinlock.
We don't need spinlock for array_cache itself, but to use array_cache for
alien_cache, array_cache structure should have spinlock. This is needless
overhead, so removing it would be better. This patch prepare it by
introducing alien_cache and using it. In the following patch,
we remove spinlock in array_cache.

Acked-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 755fb57..41b7651 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -203,6 +203,11 @@ struct array_cache {
 			 */
 };
 
+struct alien_cache {
+	spinlock_t lock;
+	struct array_cache ac;
+};
+
 #define SLAB_OBJ_PFMEMALLOC	1
 static inline bool is_obj_pfmemalloc(void *objp)
 {
@@ -458,7 +463,7 @@ static void slab_set_lock_classes(struct kmem_cache *cachep,
 		struct lock_class_key *l3_key, struct lock_class_key *alc_key,
 		int q)
 {
-	struct array_cache **alc;
+	struct alien_cache **alc;
 	struct kmem_cache_node *n;
 	int r;
 
@@ -479,7 +484,7 @@ static void slab_set_lock_classes(struct kmem_cache *cachep,
 		return;
 	for_each_node(r) {
 		if (alc[r])
-			lockdep_set_class(&alc[r]->lock, alc_key);
+			lockdep_set_class(&(alc[r]->ac.lock), alc_key);
 	}
 }
 
@@ -912,12 +917,13 @@ static int transfer_objects(struct array_cache *to,
 #define drain_alien_cache(cachep, alien) do { } while (0)
 #define reap_alien(cachep, n) do { } while (0)
 
-static inline struct array_cache **alloc_alien_cache(int node, int limit, gfp_t gfp)
+static inline struct alien_cache **alloc_alien_cache(int node,
+						int limit, gfp_t gfp)
 {
-	return (struct array_cache **)BAD_ALIEN_MAGIC;
+	return (struct alien_cache **)BAD_ALIEN_MAGIC;
 }
 
-static inline void free_alien_cache(struct array_cache **ac_ptr)
+static inline void free_alien_cache(struct alien_cache **ac_ptr)
 {
 }
 
@@ -943,40 +949,52 @@ static inline void *____cache_alloc_node(struct kmem_cache *cachep,
 static void *____cache_alloc_node(struct kmem_cache *, gfp_t, int);
 static void *alternate_node_alloc(struct kmem_cache *, gfp_t);
 
-static struct array_cache **alloc_alien_cache(int node, int limit, gfp_t gfp)
+static struct alien_cache *__alloc_alien_cache(int node, int entries,
+						int batch, gfp_t gfp)
+{
+	int memsize = sizeof(void *) * entries + sizeof(struct alien_cache);
+	struct alien_cache *alc = NULL;
+
+	alc = kmalloc_node(memsize, gfp, node);
+	init_arraycache(&alc->ac, entries, batch);
+	return alc;
+}
+
+static struct alien_cache **alloc_alien_cache(int node, int limit, gfp_t gfp)
 {
-	struct array_cache **ac_ptr;
+	struct alien_cache **alc_ptr;
 	int memsize = sizeof(void *) * nr_node_ids;
 	int i;
 
 	if (limit > 1)
 		limit = 12;
-	ac_ptr = kzalloc_node(memsize, gfp, node);
-	if (ac_ptr) {
-		for_each_node(i) {
-			if (i == node || !node_online(i))
-				continue;
-			ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d, gfp);
-			if (!ac_ptr[i]) {
-				for (i--; i >= 0; i--)
-					kfree(ac_ptr[i]);
-				kfree(ac_ptr);
-				return NULL;
-			}
+	alc_ptr = kzalloc_node(memsize, gfp, node);
+	if (!alc_ptr)
+		return NULL;
+
+	for_each_node(i) {
+		if (i == node || !node_online(i))
+			continue;
+		alc_ptr[i] = __alloc_alien_cache(node, limit, 0xbaadf00d, gfp);
+		if (!alc_ptr[i]) {
+			for (i--; i >= 0; i--)
+				kfree(alc_ptr[i]);
+			kfree(alc_ptr);
+			return NULL;
 		}
 	}
-	return ac_ptr;
+	return alc_ptr;
 }
 
-static void free_alien_cache(struct array_cache **ac_ptr)
+static void free_alien_cache(struct alien_cache **alc_ptr)
 {
 	int i;
 
-	if (!ac_ptr)
+	if (!alc_ptr)
 		return;
 	for_each_node(i)
-	    kfree(ac_ptr[i]);
-	kfree(ac_ptr);
+	    kfree(alc_ptr[i]);
+	kfree(alc_ptr);
 }
 
 static void __drain_alien_cache(struct kmem_cache *cachep,
@@ -1010,25 +1028,31 @@ static void reap_alien(struct kmem_cache *cachep, struct kmem_cache_node *n)
 	int node = __this_cpu_read(slab_reap_node);
 
 	if (n->alien) {
-		struct array_cache *ac = n->alien[node];
-
-		if (ac && ac->avail && spin_trylock_irq(&ac->lock)) {
-			__drain_alien_cache(cachep, ac, node);
-			spin_unlock_irq(&ac->lock);
+		struct alien_cache *alc = n->alien[node];
+		struct array_cache *ac;
+
+		if (alc) {
+			ac = &alc->ac;
+			if (ac->avail && spin_trylock_irq(&ac->lock)) {
+				__drain_alien_cache(cachep, ac, node);
+				spin_unlock_irq(&ac->lock);
+			}
 		}
 	}
 }
 
 static void drain_alien_cache(struct kmem_cache *cachep,
-				struct array_cache **alien)
+				struct alien_cache **alien)
 {
 	int i = 0;
+	struct alien_cache *alc;
 	struct array_cache *ac;
 	unsigned long flags;
 
 	for_each_online_node(i) {
-		ac = alien[i];
-		if (ac) {
+		alc = alien[i];
+		if (alc) {
+			ac = &alc->ac;
 			spin_lock_irqsave(&ac->lock, flags);
 			__drain_alien_cache(cachep, ac, i);
 			spin_unlock_irqrestore(&ac->lock, flags);
@@ -1040,7 +1064,8 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 {
 	int nodeid = page_to_nid(virt_to_page(objp));
 	struct kmem_cache_node *n;
-	struct array_cache *alien = NULL;
+	struct alien_cache *alien = NULL;
+	struct array_cache *ac;
 	int node;
 	LIST_HEAD(list);
 
@@ -1057,13 +1082,14 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 	STATS_INC_NODEFREES(cachep);
 	if (n->alien && n->alien[nodeid]) {
 		alien = n->alien[nodeid];
-		spin_lock(&alien->lock);
-		if (unlikely(alien->avail == alien->limit)) {
+		ac = &alien->ac;
+		spin_lock(&ac->lock);
+		if (unlikely(ac->avail == ac->limit)) {
 			STATS_INC_ACOVERFLOW(cachep);
-			__drain_alien_cache(cachep, alien, nodeid);
+			__drain_alien_cache(cachep, ac, nodeid);
 		}
-		ac_put_obj(cachep, alien, objp);
-		spin_unlock(&alien->lock);
+		ac_put_obj(cachep, ac, objp);
+		spin_unlock(&ac->lock);
 	} else {
 		spin_lock(&(cachep->node[nodeid])->list_lock);
 		free_block(cachep, &objp, 1, nodeid, &list);
@@ -1136,7 +1162,7 @@ static void cpuup_canceled(long cpu)
 	list_for_each_entry(cachep, &slab_caches, list) {
 		struct array_cache *nc;
 		struct array_cache *shared;
-		struct array_cache **alien;
+		struct alien_cache **alien;
 		LIST_HEAD(list);
 
 		/* cpu is dead; no one can alloc from it. */
@@ -1217,7 +1243,7 @@ static int cpuup_prepare(long cpu)
 	list_for_each_entry(cachep, &slab_caches, list) {
 		struct array_cache *nc;
 		struct array_cache *shared = NULL;
-		struct array_cache **alien = NULL;
+		struct alien_cache **alien = NULL;
 
 		nc = alloc_arraycache(node, cachep->limit,
 					cachep->batchcount, GFP_KERNEL);
@@ -3701,7 +3727,7 @@ static int alloc_kmem_cache_node(struct kmem_cache *cachep, gfp_t gfp)
 	int node;
 	struct kmem_cache_node *n;
 	struct array_cache *new_shared;
-	struct array_cache **new_alien = NULL;
+	struct alien_cache **new_alien = NULL;
 
 	for_each_online_node(node) {
 
diff --git a/mm/slab.h b/mm/slab.h
index 961a3fb..bacf50f 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -277,7 +277,7 @@ struct kmem_cache_node {
 	unsigned int free_limit;
 	unsigned int colour_next;	/* Per-node cache coloring */
 	struct array_cache *shared;	/* shared per node */
-	struct array_cache **alien;	/* on other nodes */
+	struct alien_cache **alien;	/* on other nodes */
 	unsigned long next_reap;	/* updated without locking */
 	int free_touched;		/* updated without locking */
 #endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 07/10] slab: use the lock on alien_cache, instead of the lock on array_cache
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (5 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 06/10] slab: introduce alien_cache Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 08/10] slab: destroy a slab without holding any alien cache lock Joonsoo Kim
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

Now, we have separate alien_cache structure, so it'd be better to hold
the lock on alien_cache while manipulating alien_cache. After that,
we don't need the lock on array_cache, so remove it.

Acked-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 41b7651..889957b 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -191,7 +191,6 @@ struct array_cache {
 	unsigned int limit;
 	unsigned int batchcount;
 	unsigned int touched;
-	spinlock_t lock;
 	void *entry[];	/*
 			 * Must have this definition in here for the proper
 			 * alignment of array_cache. Also simplifies accessing
@@ -484,7 +483,7 @@ static void slab_set_lock_classes(struct kmem_cache *cachep,
 		return;
 	for_each_node(r) {
 		if (alc[r])
-			lockdep_set_class(&(alc[r]->ac.lock), alc_key);
+			lockdep_set_class(&(alc[r]->lock), alc_key);
 	}
 }
 
@@ -761,7 +760,6 @@ static void init_arraycache(struct array_cache *ac, int limit, int batch)
 		ac->limit = limit;
 		ac->batchcount = batch;
 		ac->touched = 0;
-		spin_lock_init(&ac->lock);
 	}
 }
 
@@ -957,6 +955,7 @@ static struct alien_cache *__alloc_alien_cache(int node, int entries,
 
 	alc = kmalloc_node(memsize, gfp, node);
 	init_arraycache(&alc->ac, entries, batch);
+	spin_lock_init(&alc->lock);
 	return alc;
 }
 
@@ -1033,9 +1032,9 @@ static void reap_alien(struct kmem_cache *cachep, struct kmem_cache_node *n)
 
 		if (alc) {
 			ac = &alc->ac;
-			if (ac->avail && spin_trylock_irq(&ac->lock)) {
+			if (ac->avail && spin_trylock_irq(&alc->lock)) {
 				__drain_alien_cache(cachep, ac, node);
-				spin_unlock_irq(&ac->lock);
+				spin_unlock_irq(&alc->lock);
 			}
 		}
 	}
@@ -1053,9 +1052,9 @@ static void drain_alien_cache(struct kmem_cache *cachep,
 		alc = alien[i];
 		if (alc) {
 			ac = &alc->ac;
-			spin_lock_irqsave(&ac->lock, flags);
+			spin_lock_irqsave(&alc->lock, flags);
 			__drain_alien_cache(cachep, ac, i);
-			spin_unlock_irqrestore(&ac->lock, flags);
+			spin_unlock_irqrestore(&alc->lock, flags);
 		}
 	}
 }
@@ -1083,13 +1082,13 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 	if (n->alien && n->alien[nodeid]) {
 		alien = n->alien[nodeid];
 		ac = &alien->ac;
-		spin_lock(&ac->lock);
+		spin_lock(&alien->lock);
 		if (unlikely(ac->avail == ac->limit)) {
 			STATS_INC_ACOVERFLOW(cachep);
 			__drain_alien_cache(cachep, ac, nodeid);
 		}
 		ac_put_obj(cachep, ac, objp);
-		spin_unlock(&ac->lock);
+		spin_unlock(&alien->lock);
 	} else {
 		spin_lock(&(cachep->node[nodeid])->list_lock);
 		free_block(cachep, &objp, 1, nodeid, &list);
@@ -1558,10 +1557,6 @@ void __init kmem_cache_init(void)
 
 		memcpy(ptr, cpu_cache_get(kmem_cache),
 		       sizeof(struct arraycache_init));
-		/*
-		 * Do not assume that spinlocks can be initialized via memcpy:
-		 */
-		spin_lock_init(&ptr->lock);
 
 		kmem_cache->array[smp_processor_id()] = ptr;
 
@@ -1571,10 +1566,6 @@ void __init kmem_cache_init(void)
 		       != &initarray_generic.cache);
 		memcpy(ptr, cpu_cache_get(kmalloc_caches[INDEX_AC]),
 		       sizeof(struct arraycache_init));
-		/*
-		 * Do not assume that spinlocks can be initialized via memcpy:
-		 */
-		spin_lock_init(&ptr->lock);
 
 		kmalloc_caches[INDEX_AC]->array[smp_processor_id()] = ptr;
 	}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 08/10] slab: destroy a slab without holding any alien cache lock
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (6 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 07/10] slab: use the lock on alien_cache, instead of the lock on array_cache Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07  6:06 ` [PATCH v2 09/10] slab: remove a useless lockdep annotation Joonsoo Kim
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

I haven't heard that this alien cache lock is contended, but to reduce
chance of contention would be better generally. And with this change,
we can simplify complex lockdep annotation in slab code.
In the following patch, it will be implemented.

Acked-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 889957b..3bb5e11 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -997,9 +997,9 @@ static void free_alien_cache(struct alien_cache **alc_ptr)
 }
 
 static void __drain_alien_cache(struct kmem_cache *cachep,
-				struct array_cache *ac, int node)
+				struct array_cache *ac, int node,
+				struct list_head *list)
 {
-	LIST_HEAD(list);
 	struct kmem_cache_node *n = cachep->node[node];
 
 	if (ac->avail) {
@@ -1012,10 +1012,9 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
 		if (n->shared)
 			transfer_objects(n->shared, ac, ac->limit);
 
-		free_block(cachep, ac->entry, ac->avail, node, &list);
+		free_block(cachep, ac->entry, ac->avail, node, list);
 		ac->avail = 0;
 		spin_unlock(&n->list_lock);
-		slabs_destroy(cachep, &list);
 	}
 }
 
@@ -1033,8 +1032,11 @@ static void reap_alien(struct kmem_cache *cachep, struct kmem_cache_node *n)
 		if (alc) {
 			ac = &alc->ac;
 			if (ac->avail && spin_trylock_irq(&alc->lock)) {
-				__drain_alien_cache(cachep, ac, node);
+				LIST_HEAD(list);
+
+				__drain_alien_cache(cachep, ac, node, &list);
 				spin_unlock_irq(&alc->lock);
+				slabs_destroy(cachep, &list);
 			}
 		}
 	}
@@ -1051,10 +1053,13 @@ static void drain_alien_cache(struct kmem_cache *cachep,
 	for_each_online_node(i) {
 		alc = alien[i];
 		if (alc) {
+			LIST_HEAD(list);
+
 			ac = &alc->ac;
 			spin_lock_irqsave(&alc->lock, flags);
-			__drain_alien_cache(cachep, ac, i);
+			__drain_alien_cache(cachep, ac, i, &list);
 			spin_unlock_irqrestore(&alc->lock, flags);
+			slabs_destroy(cachep, &list);
 		}
 	}
 }
@@ -1085,10 +1090,11 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 		spin_lock(&alien->lock);
 		if (unlikely(ac->avail == ac->limit)) {
 			STATS_INC_ACOVERFLOW(cachep);
-			__drain_alien_cache(cachep, ac, nodeid);
+			__drain_alien_cache(cachep, ac, nodeid, &list);
 		}
 		ac_put_obj(cachep, ac, objp);
 		spin_unlock(&alien->lock);
+		slabs_destroy(cachep, &list);
 	} else {
 		spin_lock(&(cachep->node[nodeid])->list_lock);
 		free_block(cachep, &objp, 1, nodeid, &list);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 09/10] slab: remove a useless lockdep annotation
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (7 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 08/10] slab: destroy a slab without holding any alien cache lock Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07 14:25   ` Christoph Lameter
  2014-05-07  6:06 ` [PATCH v2 10/10] slab: remove BAD_ALIEN_MAGIC Joonsoo Kim
  2014-05-21  7:43 ` [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

Now, there is no code to hold two lock simultaneously, since
we don't call slab_destroy() with holding any lock. So, lockdep
annotation is useless now. Remove it.

v2: don't remove BAD_ALIEN_MAGIC in this patch. It will be removed
    in the following patch.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 3bb5e11..4030a89 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -439,141 +439,6 @@ static struct kmem_cache kmem_cache_boot = {
 
 #define BAD_ALIEN_MAGIC 0x01020304ul
 
-#ifdef CONFIG_LOCKDEP
-
-/*
- * Slab sometimes uses the kmalloc slabs to store the slab headers
- * for other slabs "off slab".
- * The locking for this is tricky in that it nests within the locks
- * of all other slabs in a few places; to deal with this special
- * locking we put on-slab caches into a separate lock-class.
- *
- * We set lock class for alien array caches which are up during init.
- * The lock annotation will be lost if all cpus of a node goes down and
- * then comes back up during hotplug
- */
-static struct lock_class_key on_slab_l3_key;
-static struct lock_class_key on_slab_alc_key;
-
-static struct lock_class_key debugobj_l3_key;
-static struct lock_class_key debugobj_alc_key;
-
-static void slab_set_lock_classes(struct kmem_cache *cachep,
-		struct lock_class_key *l3_key, struct lock_class_key *alc_key,
-		int q)
-{
-	struct alien_cache **alc;
-	struct kmem_cache_node *n;
-	int r;
-
-	n = cachep->node[q];
-	if (!n)
-		return;
-
-	lockdep_set_class(&n->list_lock, l3_key);
-	alc = n->alien;
-	/*
-	 * FIXME: This check for BAD_ALIEN_MAGIC
-	 * should go away when common slab code is taught to
-	 * work even without alien caches.
-	 * Currently, non NUMA code returns BAD_ALIEN_MAGIC
-	 * for alloc_alien_cache,
-	 */
-	if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
-		return;
-	for_each_node(r) {
-		if (alc[r])
-			lockdep_set_class(&(alc[r]->lock), alc_key);
-	}
-}
-
-static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
-{
-	slab_set_lock_classes(cachep, &debugobj_l3_key, &debugobj_alc_key, node);
-}
-
-static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
-{
-	int node;
-
-	for_each_online_node(node)
-		slab_set_debugobj_lock_classes_node(cachep, node);
-}
-
-static void init_node_lock_keys(int q)
-{
-	int i;
-
-	if (slab_state < UP)
-		return;
-
-	for (i = 1; i <= KMALLOC_SHIFT_HIGH; i++) {
-		struct kmem_cache_node *n;
-		struct kmem_cache *cache = kmalloc_caches[i];
-
-		if (!cache)
-			continue;
-
-		n = cache->node[q];
-		if (!n || OFF_SLAB(cache))
-			continue;
-
-		slab_set_lock_classes(cache, &on_slab_l3_key,
-				&on_slab_alc_key, q);
-	}
-}
-
-static void on_slab_lock_classes_node(struct kmem_cache *cachep, int q)
-{
-	if (!cachep->node[q])
-		return;
-
-	slab_set_lock_classes(cachep, &on_slab_l3_key,
-			&on_slab_alc_key, q);
-}
-
-static inline void on_slab_lock_classes(struct kmem_cache *cachep)
-{
-	int node;
-
-	VM_BUG_ON(OFF_SLAB(cachep));
-	for_each_node(node)
-		on_slab_lock_classes_node(cachep, node);
-}
-
-static inline void init_lock_keys(void)
-{
-	int node;
-
-	for_each_node(node)
-		init_node_lock_keys(node);
-}
-#else
-static void init_node_lock_keys(int q)
-{
-}
-
-static inline void init_lock_keys(void)
-{
-}
-
-static inline void on_slab_lock_classes(struct kmem_cache *cachep)
-{
-}
-
-static inline void on_slab_lock_classes_node(struct kmem_cache *cachep, int node)
-{
-}
-
-static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
-{
-}
-
-static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
-{
-}
-#endif
-
 static DEFINE_PER_CPU(struct delayed_work, slab_reap_work);
 
 static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep)
@@ -1293,13 +1158,7 @@ static int cpuup_prepare(long cpu)
 		spin_unlock_irq(&n->list_lock);
 		kfree(shared);
 		free_alien_cache(alien);
-		if (cachep->flags & SLAB_DEBUG_OBJECTS)
-			slab_set_debugobj_lock_classes_node(cachep, node);
-		else if (!OFF_SLAB(cachep) &&
-			 !(cachep->flags & SLAB_DESTROY_BY_RCU))
-			on_slab_lock_classes_node(cachep, node);
 	}
-	init_node_lock_keys(node);
 
 	return 0;
 bad:
@@ -1608,9 +1467,6 @@ void __init kmem_cache_init_late(void)
 			BUG();
 	mutex_unlock(&slab_mutex);
 
-	/* Annotate slab for lockdep -- annotate the malloc caches */
-	init_lock_keys();
-
 	/* Done! */
 	slab_state = FULL;
 
@@ -2386,17 +2242,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
 		return err;
 	}
 
-	if (flags & SLAB_DEBUG_OBJECTS) {
-		/*
-		 * Would deadlock through slab_destroy()->call_rcu()->
-		 * debug_object_activate()->kmem_cache_alloc().
-		 */
-		WARN_ON_ONCE(flags & SLAB_DESTROY_BY_RCU);
-
-		slab_set_debugobj_lock_classes(cachep);
-	} else if (!OFF_SLAB(cachep) && !(flags & SLAB_DESTROY_BY_RCU))
-		on_slab_lock_classes(cachep);
-
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 10/10] slab: remove BAD_ALIEN_MAGIC
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (8 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 09/10] slab: remove a useless lockdep annotation Joonsoo Kim
@ 2014-05-07  6:06 ` Joonsoo Kim
  2014-05-07 14:24   ` Christoph Lameter
  2014-05-21  7:43 ` [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
  10 siblings, 1 reply; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-07  6:06 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim, Joonsoo Kim

BAD_ALIEN_MAGIC value isn't used anymore. So remove it.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/slab.c b/mm/slab.c
index 4030a89..8476ffc 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -437,8 +437,6 @@ static struct kmem_cache kmem_cache_boot = {
 	.name = "kmem_cache",
 };
 
-#define BAD_ALIEN_MAGIC 0x01020304ul
-
 static DEFINE_PER_CPU(struct delayed_work, slab_reap_work);
 
 static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep)
@@ -783,7 +781,7 @@ static int transfer_objects(struct array_cache *to,
 static inline struct alien_cache **alloc_alien_cache(int node,
 						int limit, gfp_t gfp)
 {
-	return (struct alien_cache **)BAD_ALIEN_MAGIC;
+	return NULL;
 }
 
 static inline void free_alien_cache(struct alien_cache **ac_ptr)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 01/10] slab: add unlikely macro to help compiler
  2014-05-07  6:06 ` [PATCH v2 01/10] slab: add unlikely macro to help compiler Joonsoo Kim
@ 2014-05-07 14:21   ` Christoph Lameter
  0 siblings, 0 replies; 19+ messages in thread
From: Christoph Lameter @ 2014-05-07 14:21 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> slab_should_failslab() is called on every allocation, so to optimize it
> is reasonable. We normally don't allocate from kmem_cache. It is just
> used when new kmem_cache is created, so it's very rare case. Therefore,
> add unlikely macro to help compiler optimization.

Acked-by: Christoph Lameter <cl@linux.com>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 02/10] slab: makes clear_obj_pfmemalloc() just return masked value
  2014-05-07  6:06 ` [PATCH v2 02/10] slab: makes clear_obj_pfmemalloc() just return masked value Joonsoo Kim
@ 2014-05-07 14:22   ` Christoph Lameter
  0 siblings, 0 replies; 19+ messages in thread
From: Christoph Lameter @ 2014-05-07 14:22 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> clear_obj_pfmemalloc() takes the pointer to pointer to store masked value
> back into this address. But this is useless, since we don't use this stored
> value anymore. All we need is just masked value so makes clear_obj_pfmemalloc()
> just return masked value.

Acked-by: Christoph Lameter <cl@linux.com>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 10/10] slab: remove BAD_ALIEN_MAGIC
  2014-05-07  6:06 ` [PATCH v2 10/10] slab: remove BAD_ALIEN_MAGIC Joonsoo Kim
@ 2014-05-07 14:24   ` Christoph Lameter
  0 siblings, 0 replies; 19+ messages in thread
From: Christoph Lameter @ 2014-05-07 14:24 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> BAD_ALIEN_MAGIC value isn't used anymore. So remove it.

Acked-by: Christoph Lameter <cl@linux.com>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 09/10] slab: remove a useless lockdep annotation
  2014-05-07  6:06 ` [PATCH v2 09/10] slab: remove a useless lockdep annotation Joonsoo Kim
@ 2014-05-07 14:25   ` Christoph Lameter
  0 siblings, 0 replies; 19+ messages in thread
From: Christoph Lameter @ 2014-05-07 14:25 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Andrew Morton, David Rientjes, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> Now, there is no code to hold two lock simultaneously, since
> we don't call slab_destroy() with holding any lock. So, lockdep
> annotation is useless now. Remove it.

Acked-by: Christoph Lameter <cl@linux.com>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 03/10] slab: move up code to get kmem_cache_node in free_block()
  2014-05-07  6:06 ` [PATCH v2 03/10] slab: move up code to get kmem_cache_node in free_block() Joonsoo Kim
@ 2014-05-08  0:52   ` David Rientjes
  0 siblings, 0 replies; 19+ messages in thread
From: David Rientjes @ 2014-05-08  0:52 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Christoph Lameter, Andrew Morton, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> node isn't changed, so we don't need to retreive this structure
> everytime we move the object. Maybe compiler do this optimization,
> but making it explicitly is better.
> 
> Acked-by: Christoph Lameter <cl@linux.com>
> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

Acked-by: David Rientjes <rientjes@google.com>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 04/10] slab: defer slab_destroy in free_block()
  2014-05-07  6:06 ` [PATCH v2 04/10] slab: defer slab_destroy " Joonsoo Kim
@ 2014-05-08  1:01   ` David Rientjes
  0 siblings, 0 replies; 19+ messages in thread
From: David Rientjes @ 2014-05-08  1:01 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Christoph Lameter, Andrew Morton, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> In free_block(), if freeing object makes new free slab and number of
> free_objects exceeds free_limit, we start to destroy this new free slab
> with holding the kmem_cache node lock. Holding the lock is useless and,
> generally, holding a lock as least as possible is good thing. I never
> measure performance effect of this, but we'd be better not to hold the lock
> as much as possible.
> 
> Commented by Christoph:
>   This is also good because kmem_cache_free is no longer called while
>   holding the node lock. So we avoid one case of recursion.
> 
> Acked-by: Christoph Lameter <cl@linux.com>
> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

Acked-by: David Rientjes <rientjes@google.com>

Nice optimization.  I think it could have benefited from a comment 
describing what the free_block() list formal is, though.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 05/10] slab: factor out initialization of arracy cache
  2014-05-07  6:06 ` [PATCH v2 05/10] slab: factor out initialization of arracy cache Joonsoo Kim
@ 2014-05-08  1:19   ` David Rientjes
  0 siblings, 0 replies; 19+ messages in thread
From: David Rientjes @ 2014-05-08  1:19 UTC (permalink / raw)
  To: Joonsoo Kim
  Cc: Pekka Enberg, Christoph Lameter, Andrew Morton, linux-mm,
	linux-kernel, Joonsoo Kim

On Wed, 7 May 2014, Joonsoo Kim wrote:

> Factor out initialization of array cache to use it in following patch.
> 
> Acked-by: Christoph Lameter <cl@linux.com>
> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
> 

Acked-by: David Rientjes <rientjes@google.com>

s/arracy/array/ in patch title.

> diff --git a/mm/slab.c b/mm/slab.c
> index 7647728..755fb57 100644
> --- a/mm/slab.c
> +++ b/mm/slab.c
> @@ -741,13 +741,8 @@ static void start_cpu_timer(int cpu)
>  	}
>  }
>  
> -static struct array_cache *alloc_arraycache(int node, int entries,
> -					    int batchcount, gfp_t gfp)
> +static void init_arraycache(struct array_cache *ac, int limit, int batch)
>  {
> -	int memsize = sizeof(void *) * entries + sizeof(struct array_cache);
> -	struct array_cache *nc = NULL;
> -
> -	nc = kmalloc_node(memsize, gfp, node);
>  	/*
>  	 * The array_cache structures contain pointers to free object.
>  	 * However, when such objects are allocated or transferred to another
> @@ -755,15 +750,25 @@ static struct array_cache *alloc_arraycache(int node, int entries,
>  	 * valid references during a kmemleak scan. Therefore, kmemleak must
>  	 * not scan such objects.
>  	 */
> -	kmemleak_no_scan(nc);
> -	if (nc) {
> -		nc->avail = 0;
> -		nc->limit = entries;
> -		nc->batchcount = batchcount;
> -		nc->touched = 0;
> -		spin_lock_init(&nc->lock);
> +	kmemleak_no_scan(ac);
> +	if (ac) {
> +		ac->avail = 0;
> +		ac->limit = limit;
> +		ac->batchcount = batch;
> +		ac->touched = 0;
> +		spin_lock_init(&ac->lock);
>  	}
> -	return nc;
> +}
> +
> +static struct array_cache *alloc_arraycache(int node, int entries,
> +					    int batchcount, gfp_t gfp)
> +{
> +	int memsize = sizeof(void *) * entries + sizeof(struct array_cache);

const?

> +	struct array_cache *ac = NULL;
> +
> +	ac = kmalloc_node(memsize, gfp, node);

I thought nc meant node cache, but I agree that ac is clearer.

> +	init_arraycache(ac, entries, batchcount);
> +	return ac;
>  }
>  
>  static inline bool is_slab_pfmemalloc(struct page *page)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB
  2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
                   ` (9 preceding siblings ...)
  2014-05-07  6:06 ` [PATCH v2 10/10] slab: remove BAD_ALIEN_MAGIC Joonsoo Kim
@ 2014-05-21  7:43 ` Joonsoo Kim
  10 siblings, 0 replies; 19+ messages in thread
From: Joonsoo Kim @ 2014-05-21  7:43 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Christoph Lameter, Andrew Morton, David Rientjes, linux-mm, linux-kernel

On Wed, May 07, 2014 at 03:06:10PM +0900, Joonsoo Kim wrote:
> This patchset does some clean-up and tries to remove lockdep annotation.
> 
> Patches 1~3 are just for really really minor improvement.
> Patches 4~10 are for clean-up and removing lockdep annotation.
> 
> There are two cases that lockdep annotation is needed in SLAB.
> 1) holding two node locks
> 2) holding two array cache(alien cache) locks
> 
> I looked at the code and found that we can avoid these cases without
> any negative effect.
> 
> 1) occurs if freeing object makes new free slab and we decide to
> destroy it. Although we don't need to hold the lock during destroying
> a slab, current code do that. Destroying a slab without holding the lock
> would help the reduction of the lock contention. To do it, I change the
> implementation that new free slab is destroyed after releasing the lock.
> 
> 2) occurs on similar situation. When we free object from non-local node,
> we put this object to alien cache with holding the alien cache lock.
> If alien cache is full, we try to flush alien cache to proper node cache,
> and, in this time, new free slab could be made. Destroying it would be
> started and we will free metadata object which comes from another node.
> In this case, we need another node's alien cache lock to free object.
> This forces us to hold two array cache locks and then we need lockdep
> annotation although they are always different locks and deadlock cannot
> be possible. To prevent this situation, I use same way as 1).
> 
> In this way, we can avoid 1) and 2) cases, and then, can remove lockdep
> annotation. As short stat noted, this makes SLAB code much simpler.
> 
> Many of this series get Ack from Christoph Lameter on previous iteration,
> but 1, 2, 9 and 10 need to get Ack. There is no big change from previous
> iteration. It is just rebased on current linux-next.
> 
> Thanks.
> 
> Joonsoo Kim (10):
>   slab: add unlikely macro to help compiler
>   slab: makes clear_obj_pfmemalloc() just return masked value
>   slab: move up code to get kmem_cache_node in free_block()
>   slab: defer slab_destroy in free_block()
>   slab: factor out initialization of arracy cache
>   slab: introduce alien_cache
>   slab: use the lock on alien_cache, instead of the lock on array_cache
>   slab: destroy a slab without holding any alien cache lock
>   slab: remove a useless lockdep annotation
>   slab: remove BAD_ALIEN_MAGIC
> 
>  mm/slab.c |  391 ++++++++++++++++++++++---------------------------------------
>  mm/slab.h |    2 +-
>  2 files changed, 140 insertions(+), 253 deletions(-)

Hello, Andrew.

Pekka seems to be busy.
Could you manage this patchset?

Thanks.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2014-05-21  7:41 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-07  6:06 [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim
2014-05-07  6:06 ` [PATCH v2 01/10] slab: add unlikely macro to help compiler Joonsoo Kim
2014-05-07 14:21   ` Christoph Lameter
2014-05-07  6:06 ` [PATCH v2 02/10] slab: makes clear_obj_pfmemalloc() just return masked value Joonsoo Kim
2014-05-07 14:22   ` Christoph Lameter
2014-05-07  6:06 ` [PATCH v2 03/10] slab: move up code to get kmem_cache_node in free_block() Joonsoo Kim
2014-05-08  0:52   ` David Rientjes
2014-05-07  6:06 ` [PATCH v2 04/10] slab: defer slab_destroy " Joonsoo Kim
2014-05-08  1:01   ` David Rientjes
2014-05-07  6:06 ` [PATCH v2 05/10] slab: factor out initialization of arracy cache Joonsoo Kim
2014-05-08  1:19   ` David Rientjes
2014-05-07  6:06 ` [PATCH v2 06/10] slab: introduce alien_cache Joonsoo Kim
2014-05-07  6:06 ` [PATCH v2 07/10] slab: use the lock on alien_cache, instead of the lock on array_cache Joonsoo Kim
2014-05-07  6:06 ` [PATCH v2 08/10] slab: destroy a slab without holding any alien cache lock Joonsoo Kim
2014-05-07  6:06 ` [PATCH v2 09/10] slab: remove a useless lockdep annotation Joonsoo Kim
2014-05-07 14:25   ` Christoph Lameter
2014-05-07  6:06 ` [PATCH v2 10/10] slab: remove BAD_ALIEN_MAGIC Joonsoo Kim
2014-05-07 14:24   ` Christoph Lameter
2014-05-21  7:43 ` [PATCH v2 00/10] clean-up and remove lockdep annotation in SLAB Joonsoo Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).