diff options
Diffstat (limited to 'mm/slab.c')
| -rw-r--r-- | mm/slab.c | 99 | 
1 files changed, 75 insertions, 24 deletions
diff --git a/mm/slab.c b/mm/slab.c index 1e523ed47c6..6d90a091fdc 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -622,6 +622,51 @@ int slab_is_available(void)  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 array_cache **alc; +	struct kmem_list3 *l3; +	int r; + +	l3 = cachep->nodelists[q]; +	if (!l3) +		return; + +	lockdep_set_class(&l3->list_lock, l3_key); +	alc = l3->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)  {  	struct cache_sizes *s = malloc_sizes; @@ -630,29 +675,14 @@ static void init_node_lock_keys(int q)  		return;  	for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) { -		struct array_cache **alc;  		struct kmem_list3 *l3; -		int r;  		l3 = s->cs_cachep->nodelists[q];  		if (!l3 || OFF_SLAB(s->cs_cachep))  			continue; -		lockdep_set_class(&l3->list_lock, &on_slab_l3_key); -		alc = l3->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) -			continue; -		for_each_node(r) { -			if (alc[r]) -				lockdep_set_class(&alc[r]->lock, -					&on_slab_alc_key); -		} + +		slab_set_lock_classes(s->cs_cachep, &on_slab_l3_key, +				&on_slab_alc_key, q);  	}  } @@ -671,6 +701,14 @@ static void init_node_lock_keys(int q)  static inline void init_lock_keys(void)  {  } + +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  /* @@ -1264,6 +1302,8 @@ static int __cpuinit cpuup_prepare(long cpu)  		spin_unlock_irq(&l3->list_lock);  		kfree(shared);  		free_alien_cache(alien); +		if (cachep->flags & SLAB_DEBUG_OBJECTS) +			slab_set_debugobj_lock_classes_node(cachep, node);  	}  	init_node_lock_keys(node); @@ -1626,6 +1666,9 @@ void __init kmem_cache_init_late(void)  {  	struct kmem_cache *cachep; +	/* Annotate slab for lockdep -- annotate the malloc caches */ +	init_lock_keys(); +  	/* 6) resize the head arrays to their final sizes */  	mutex_lock(&cache_chain_mutex);  	list_for_each_entry(cachep, &cache_chain, next) @@ -1636,9 +1679,6 @@ void __init kmem_cache_init_late(void)  	/* Done! */  	g_cpucache_up = FULL; -	/* Annotate slab for lockdep -- annotate the malloc caches */ -	init_lock_keys(); -  	/*  	 * Register a cpu startup notifier callback that initializes  	 * cpu_cache_get for all new cpus @@ -2426,6 +2466,16 @@ kmem_cache_create (const char *name, size_t size, size_t align,  		goto oops;  	} +	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); +	} +  	/* cache setup completed, link it into the list */  	list_add(&cachep->next, &cache_chain);  oops: @@ -3403,7 +3453,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,  	cache_alloc_debugcheck_before(cachep, flags);  	local_irq_save(save_flags); -	if (nodeid == -1) +	if (nodeid == NUMA_NO_NODE)  		nodeid = slab_node;  	if (unlikely(!cachep->nodelists[nodeid])) { @@ -3934,7 +3984,7 @@ fail:  struct ccupdate_struct {  	struct kmem_cache *cachep; -	struct array_cache *new[NR_CPUS]; +	struct array_cache *new[0];  };  static void do_ccupdate_local(void *info) @@ -3956,7 +4006,8 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,  	struct ccupdate_struct *new;  	int i; -	new = kzalloc(sizeof(*new), gfp); +	new = kzalloc(sizeof(*new) + nr_cpu_ids * sizeof(struct array_cache *), +		      gfp);  	if (!new)  		return -ENOMEM;  |