mm/sl[aou]b: Extract a common function for kmem_cache_destroy
kmem_cache_destroy does basically the same in all allocators. Extract common code which is easy since we already have common mutex handling. Reviewed-by: Glauber Costa <glommer@parallels.com> Signed-off-by: Christoph Lameter <cl@linux.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
		
					parent
					
						
							
								7c9adf5a54
							
						
					
				
			
			
				commit
				
					
						945cf2b619
					
				
			
		
					 5 changed files with 49 additions and 75 deletions
				
			
		
							
								
								
									
										45
									
								
								mm/slab.c
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								mm/slab.c
									
										
									
									
									
								
							|  | @ -2206,7 +2206,7 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void __kmem_cache_destroy(struct kmem_cache *cachep) | void __kmem_cache_destroy(struct kmem_cache *cachep) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	struct kmem_list3 *l3; | 	struct kmem_list3 *l3; | ||||||
|  | @ -2763,49 +2763,10 @@ int kmem_cache_shrink(struct kmem_cache *cachep) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(kmem_cache_shrink); | EXPORT_SYMBOL(kmem_cache_shrink); | ||||||
| 
 | 
 | ||||||
| /**
 | int __kmem_cache_shutdown(struct kmem_cache *cachep) | ||||||
|  * kmem_cache_destroy - delete a cache |  | ||||||
|  * @cachep: the cache to destroy |  | ||||||
|  * |  | ||||||
|  * Remove a &struct kmem_cache object from the slab cache. |  | ||||||
|  * |  | ||||||
|  * It is expected this function will be called by a module when it is |  | ||||||
|  * unloaded.  This will remove the cache completely, and avoid a duplicate |  | ||||||
|  * cache being allocated each time a module is loaded and unloaded, if the |  | ||||||
|  * module doesn't have persistent in-kernel storage across loads and unloads. |  | ||||||
|  * |  | ||||||
|  * The cache must be empty before calling this function. |  | ||||||
|  * |  | ||||||
|  * The caller must guarantee that no one will allocate memory from the cache |  | ||||||
|  * during the kmem_cache_destroy(). |  | ||||||
|  */ |  | ||||||
| void kmem_cache_destroy(struct kmem_cache *cachep) |  | ||||||
| { | { | ||||||
| 	BUG_ON(!cachep || in_interrupt()); | 	return __cache_shrink(cachep); | ||||||
| 
 |  | ||||||
| 	/* Find the cache in the chain of caches. */ |  | ||||||
| 	get_online_cpus(); |  | ||||||
| 	mutex_lock(&slab_mutex); |  | ||||||
| 	/*
 |  | ||||||
| 	 * the chain is never empty, cache_cache is never destroyed |  | ||||||
| 	 */ |  | ||||||
| 	list_del(&cachep->list); |  | ||||||
| 	if (__cache_shrink(cachep)) { |  | ||||||
| 		slab_error(cachep, "Can't free all objects"); |  | ||||||
| 		list_add(&cachep->list, &slab_caches); |  | ||||||
| 		mutex_unlock(&slab_mutex); |  | ||||||
| 		put_online_cpus(); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) |  | ||||||
| 		rcu_barrier(); |  | ||||||
| 
 |  | ||||||
| 	__kmem_cache_destroy(cachep); |  | ||||||
| 	mutex_unlock(&slab_mutex); |  | ||||||
| 	put_online_cpus(); |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(kmem_cache_destroy); |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Get the memory for a slab management obj. |  * Get the memory for a slab management obj. | ||||||
|  |  | ||||||
|  | @ -30,4 +30,7 @@ extern struct list_head slab_caches; | ||||||
| struct kmem_cache *__kmem_cache_create(const char *name, size_t size, | struct kmem_cache *__kmem_cache_create(const char *name, size_t size, | ||||||
| 	size_t align, unsigned long flags, void (*ctor)(void *)); | 	size_t align, unsigned long flags, void (*ctor)(void *)); | ||||||
| 
 | 
 | ||||||
|  | int __kmem_cache_shutdown(struct kmem_cache *); | ||||||
|  | void __kmem_cache_destroy(struct kmem_cache *); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -140,6 +140,31 @@ out_locked: | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(kmem_cache_create); | EXPORT_SYMBOL(kmem_cache_create); | ||||||
| 
 | 
 | ||||||
|  | void kmem_cache_destroy(struct kmem_cache *s) | ||||||
|  | { | ||||||
|  | 	get_online_cpus(); | ||||||
|  | 	mutex_lock(&slab_mutex); | ||||||
|  | 	s->refcount--; | ||||||
|  | 	if (!s->refcount) { | ||||||
|  | 		list_del(&s->list); | ||||||
|  | 
 | ||||||
|  | 		if (!__kmem_cache_shutdown(s)) { | ||||||
|  | 			if (s->flags & SLAB_DESTROY_BY_RCU) | ||||||
|  | 				rcu_barrier(); | ||||||
|  | 
 | ||||||
|  | 			__kmem_cache_destroy(s); | ||||||
|  | 		} else { | ||||||
|  | 			list_add(&s->list, &slab_caches); | ||||||
|  | 			printk(KERN_ERR "kmem_cache_destroy %s: Slab cache still has objects\n", | ||||||
|  | 				s->name); | ||||||
|  | 			dump_stack(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&slab_mutex); | ||||||
|  | 	put_online_cpus(); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(kmem_cache_destroy); | ||||||
|  | 
 | ||||||
| int slab_is_available(void) | int slab_is_available(void) | ||||||
| { | { | ||||||
| 	return slab_state >= UP; | 	return slab_state >= UP; | ||||||
|  |  | ||||||
							
								
								
									
										15
									
								
								mm/slob.c
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								mm/slob.c
									
										
									
									
									
								
							|  | @ -538,18 +538,11 @@ struct kmem_cache *__kmem_cache_create(const char *name, size_t size, | ||||||
| 	return c; | 	return c; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kmem_cache_destroy(struct kmem_cache *c) | void __kmem_cache_destroy(struct kmem_cache *c) | ||||||
| { | { | ||||||
| 	mutex_lock(&slab_mutex); |  | ||||||
| 	list_del(&c->list); |  | ||||||
| 	mutex_unlock(&slab_mutex); |  | ||||||
| 
 |  | ||||||
| 	kmemleak_free(c); | 	kmemleak_free(c); | ||||||
| 	if (c->flags & SLAB_DESTROY_BY_RCU) |  | ||||||
| 		rcu_barrier(); |  | ||||||
| 	slob_free(c, sizeof(struct kmem_cache)); | 	slob_free(c, sizeof(struct kmem_cache)); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(kmem_cache_destroy); |  | ||||||
| 
 | 
 | ||||||
| void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) | void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) | ||||||
| { | { | ||||||
|  | @ -617,6 +610,12 @@ unsigned int kmem_cache_size(struct kmem_cache *c) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(kmem_cache_size); | EXPORT_SYMBOL(kmem_cache_size); | ||||||
| 
 | 
 | ||||||
|  | int __kmem_cache_shutdown(struct kmem_cache *c) | ||||||
|  | { | ||||||
|  | 	/* No way to check for remaining objects */ | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int kmem_cache_shrink(struct kmem_cache *d) | int kmem_cache_shrink(struct kmem_cache *d) | ||||||
| { | { | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								mm/slub.c
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								mm/slub.c
									
										
									
									
									
								
							|  | @ -624,7 +624,7 @@ static void object_err(struct kmem_cache *s, struct page *page, | ||||||
| 	print_trailer(s, page, object); | 	print_trailer(s, page, object); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void slab_err(struct kmem_cache *s, struct page *page, char *fmt, ...) | static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...) | ||||||
| { | { | ||||||
| 	va_list args; | 	va_list args; | ||||||
| 	char buf[100]; | 	char buf[100]; | ||||||
|  | @ -3146,7 +3146,7 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page, | ||||||
| 				     sizeof(long), GFP_ATOMIC); | 				     sizeof(long), GFP_ATOMIC); | ||||||
| 	if (!map) | 	if (!map) | ||||||
| 		return; | 		return; | ||||||
| 	slab_err(s, page, "%s", text); | 	slab_err(s, page, text, s->name); | ||||||
| 	slab_lock(page); | 	slab_lock(page); | ||||||
| 
 | 
 | ||||||
| 	get_map(s, page, map); | 	get_map(s, page, map); | ||||||
|  | @ -3178,7 +3178,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n) | ||||||
| 			discard_slab(s, page); | 			discard_slab(s, page); | ||||||
| 		} else { | 		} else { | ||||||
| 			list_slab_objects(s, page, | 			list_slab_objects(s, page, | ||||||
| 				"Objects remaining on kmem_cache_close()"); | 			"Objects remaining in %s on kmem_cache_close()"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -3191,7 +3191,6 @@ static inline int kmem_cache_close(struct kmem_cache *s) | ||||||
| 	int node; | 	int node; | ||||||
| 
 | 
 | ||||||
| 	flush_all(s); | 	flush_all(s); | ||||||
| 	free_percpu(s->cpu_slab); |  | ||||||
| 	/* Attempt to free all objects */ | 	/* Attempt to free all objects */ | ||||||
| 	for_each_node_state(node, N_NORMAL_MEMORY) { | 	for_each_node_state(node, N_NORMAL_MEMORY) { | ||||||
| 		struct kmem_cache_node *n = get_node(s, node); | 		struct kmem_cache_node *n = get_node(s, node); | ||||||
|  | @ -3200,33 +3199,20 @@ static inline int kmem_cache_close(struct kmem_cache *s) | ||||||
| 		if (n->nr_partial || slabs_node(s, node)) | 		if (n->nr_partial || slabs_node(s, node)) | ||||||
| 			return 1; | 			return 1; | ||||||
| 	} | 	} | ||||||
|  | 	free_percpu(s->cpu_slab); | ||||||
| 	free_kmem_cache_nodes(s); | 	free_kmem_cache_nodes(s); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | int __kmem_cache_shutdown(struct kmem_cache *s) | ||||||
|  * Close a cache and release the kmem_cache structure |  | ||||||
|  * (must be used for caches created using kmem_cache_create) |  | ||||||
|  */ |  | ||||||
| void kmem_cache_destroy(struct kmem_cache *s) |  | ||||||
| { | { | ||||||
| 	mutex_lock(&slab_mutex); | 	return kmem_cache_close(s); | ||||||
| 	s->refcount--; | } | ||||||
| 	if (!s->refcount) { | 
 | ||||||
| 		list_del(&s->list); | void __kmem_cache_destroy(struct kmem_cache *s) | ||||||
| 		mutex_unlock(&slab_mutex); | { | ||||||
| 		if (kmem_cache_close(s)) { | 	sysfs_slab_remove(s); | ||||||
| 			printk(KERN_ERR "SLUB %s: %s called for cache that " |  | ||||||
| 				"still has objects.\n", s->name, __func__); |  | ||||||
| 			dump_stack(); |  | ||||||
| 		} |  | ||||||
| 		if (s->flags & SLAB_DESTROY_BY_RCU) |  | ||||||
| 			rcu_barrier(); |  | ||||||
| 		sysfs_slab_remove(s); |  | ||||||
| 	} else |  | ||||||
| 		mutex_unlock(&slab_mutex); |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(kmem_cache_destroy); |  | ||||||
| 
 | 
 | ||||||
| /********************************************************************
 | /********************************************************************
 | ||||||
|  *		Kmalloc subsystem |  *		Kmalloc subsystem | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Christoph Lameter
				Christoph Lameter