mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	slub: use sysfs'es release mechanism for kmem_cache
debugobjects warning during netfilter exit:
    ------------[ cut here ]------------
    WARNING: CPU: 6 PID: 4178 at lib/debugobjects.c:260 debug_print_object+0x8d/0xb0()
    ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x20
    Modules linked in:
    CPU: 6 PID: 4178 Comm: kworker/u16:2 Tainted: G        W 3.11.0-next-20130906-sasha #3984
    Workqueue: netns cleanup_net
    Call Trace:
      dump_stack+0x52/0x87
      warn_slowpath_common+0x8c/0xc0
      warn_slowpath_fmt+0x46/0x50
      debug_print_object+0x8d/0xb0
      __debug_check_no_obj_freed+0xa5/0x220
      debug_check_no_obj_freed+0x15/0x20
      kmem_cache_free+0x197/0x340
      kmem_cache_destroy+0x86/0xe0
      nf_conntrack_cleanup_net_list+0x131/0x170
      nf_conntrack_pernet_exit+0x5d/0x70
      ops_exit_list+0x5e/0x70
      cleanup_net+0xfb/0x1c0
      process_one_work+0x338/0x550
      worker_thread+0x215/0x350
      kthread+0xe7/0xf0
      ret_from_fork+0x7c/0xb0
Also during dcookie cleanup:
    WARNING: CPU: 12 PID: 9725 at lib/debugobjects.c:260 debug_print_object+0x8c/0xb0()
    ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x20
    Modules linked in:
    CPU: 12 PID: 9725 Comm: trinity-c141 Not tainted 3.15.0-rc2-next-20140423-sasha-00018-gc4ff6c4 #408
    Call Trace:
      dump_stack (lib/dump_stack.c:52)
      warn_slowpath_common (kernel/panic.c:430)
      warn_slowpath_fmt (kernel/panic.c:445)
      debug_print_object (lib/debugobjects.c:262)
      __debug_check_no_obj_freed (lib/debugobjects.c:697)
      debug_check_no_obj_freed (lib/debugobjects.c:726)
      kmem_cache_free (mm/slub.c:2689 mm/slub.c:2717)
      kmem_cache_destroy (mm/slab_common.c:363)
      dcookie_unregister (fs/dcookies.c:302 fs/dcookies.c:343)
      event_buffer_release (arch/x86/oprofile/../../../drivers/oprofile/event_buffer.c:153)
      __fput (fs/file_table.c:217)
      ____fput (fs/file_table.c:253)
      task_work_run (kernel/task_work.c:125 (discriminator 1))
      do_notify_resume (include/linux/tracehook.h:196 arch/x86/kernel/signal.c:751)
      int_signal (arch/x86/kernel/entry_64.S:807)
Sysfs has a release mechanism.  Use that to release the kmem_cache
structure if CONFIG_SYSFS is enabled.
Only slub is changed - slab currently only supports /proc/slabinfo and
not /sys/kernel/slab/*.  We talked about adding that and someone was
working on it.
[akpm@linux-foundation.org: fix CONFIG_SYSFS=n build]
[akpm@linux-foundation.org: fix CONFIG_SYSFS=n build even more]
Signed-off-by: Christoph Lameter <cl@linux.com>
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Tested-by: Sasha Levin <sasha.levin@oracle.com>
Acked-by: Greg KH <greg@kroah.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									623762517e
								
							
						
					
					
						commit
						41a212859a
					
				
					 4 changed files with 29 additions and 24 deletions
				
			
		| 
						 | 
					@ -101,4 +101,13 @@ struct kmem_cache {
 | 
				
			||||||
	struct kmem_cache_node *node[MAX_NUMNODES];
 | 
						struct kmem_cache_node *node[MAX_NUMNODES];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_SYSFS
 | 
				
			||||||
 | 
					#define SLAB_SUPPORTS_SYSFS
 | 
				
			||||||
 | 
					void sysfs_slab_remove(struct kmem_cache *);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void sysfs_slab_remove(struct kmem_cache *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _LINUX_SLUB_DEF_H */
 | 
					#endif /* _LINUX_SLUB_DEF_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,6 +91,7 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
 | 
				
			||||||
#define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS)
 | 
					#define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __kmem_cache_shutdown(struct kmem_cache *);
 | 
					int __kmem_cache_shutdown(struct kmem_cache *);
 | 
				
			||||||
 | 
					void slab_kmem_cache_release(struct kmem_cache *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct seq_file;
 | 
					struct seq_file;
 | 
				
			||||||
struct file;
 | 
					struct file;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -323,6 +323,12 @@ static int kmem_cache_destroy_memcg_children(struct kmem_cache *s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_MEMCG_KMEM */
 | 
					#endif /* CONFIG_MEMCG_KMEM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void slab_kmem_cache_release(struct kmem_cache *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						kfree(s->name);
 | 
				
			||||||
 | 
						kmem_cache_free(kmem_cache, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void kmem_cache_destroy(struct kmem_cache *s)
 | 
					void kmem_cache_destroy(struct kmem_cache *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	get_online_cpus();
 | 
						get_online_cpus();
 | 
				
			||||||
| 
						 | 
					@ -352,8 +358,11 @@ void kmem_cache_destroy(struct kmem_cache *s)
 | 
				
			||||||
		rcu_barrier();
 | 
							rcu_barrier();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcg_free_cache_params(s);
 | 
						memcg_free_cache_params(s);
 | 
				
			||||||
	kfree(s->name);
 | 
					#ifdef SLAB_SUPPORTS_SYSFS
 | 
				
			||||||
	kmem_cache_free(kmem_cache, s);
 | 
						sysfs_slab_remove(s);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						slab_kmem_cache_release(s);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	goto out_put_cpus;
 | 
						goto out_put_cpus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_unlock:
 | 
					out_unlock:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								mm/slub.c
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								mm/slub.c
									
									
									
									
									
								
							| 
						 | 
					@ -210,14 +210,11 @@ enum track_item { TRACK_ALLOC, TRACK_FREE };
 | 
				
			||||||
#ifdef CONFIG_SYSFS
 | 
					#ifdef CONFIG_SYSFS
 | 
				
			||||||
static int sysfs_slab_add(struct kmem_cache *);
 | 
					static int sysfs_slab_add(struct kmem_cache *);
 | 
				
			||||||
static int sysfs_slab_alias(struct kmem_cache *, const char *);
 | 
					static int sysfs_slab_alias(struct kmem_cache *, const char *);
 | 
				
			||||||
static void sysfs_slab_remove(struct kmem_cache *);
 | 
					 | 
				
			||||||
static void memcg_propagate_slab_attrs(struct kmem_cache *s);
 | 
					static void memcg_propagate_slab_attrs(struct kmem_cache *s);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; }
 | 
					static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; }
 | 
				
			||||||
static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
 | 
					static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
 | 
				
			||||||
							{ return 0; }
 | 
												{ return 0; }
 | 
				
			||||||
static inline void sysfs_slab_remove(struct kmem_cache *s) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void memcg_propagate_slab_attrs(struct kmem_cache *s) { }
 | 
					static inline void memcg_propagate_slab_attrs(struct kmem_cache *s) { }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3238,24 +3235,7 @@ static inline int kmem_cache_close(struct kmem_cache *s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __kmem_cache_shutdown(struct kmem_cache *s)
 | 
					int __kmem_cache_shutdown(struct kmem_cache *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = kmem_cache_close(s);
 | 
						return kmem_cache_close(s);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!rc) {
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Since slab_attr_store may take the slab_mutex, we should
 | 
					 | 
				
			||||||
		 * release the lock while removing the sysfs entry in order to
 | 
					 | 
				
			||||||
		 * avoid a deadlock. Because this is pretty much the last
 | 
					 | 
				
			||||||
		 * operation we do and the lock will be released shortly after
 | 
					 | 
				
			||||||
		 * that in slab_common.c, we could just move sysfs_slab_remove
 | 
					 | 
				
			||||||
		 * to a later point in common code. We should do that when we
 | 
					 | 
				
			||||||
		 * have a common sysfs framework for all allocators.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		mutex_unlock(&slab_mutex);
 | 
					 | 
				
			||||||
		sysfs_slab_remove(s);
 | 
					 | 
				
			||||||
		mutex_lock(&slab_mutex);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/********************************************************************
 | 
					/********************************************************************
 | 
				
			||||||
| 
						 | 
					@ -5122,6 +5102,11 @@ static void memcg_propagate_slab_attrs(struct kmem_cache *s)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kmem_cache_release(struct kobject *k)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						slab_kmem_cache_release(to_slab(k));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct sysfs_ops slab_sysfs_ops = {
 | 
					static const struct sysfs_ops slab_sysfs_ops = {
 | 
				
			||||||
	.show = slab_attr_show,
 | 
						.show = slab_attr_show,
 | 
				
			||||||
	.store = slab_attr_store,
 | 
						.store = slab_attr_store,
 | 
				
			||||||
| 
						 | 
					@ -5129,6 +5114,7 @@ static const struct sysfs_ops slab_sysfs_ops = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct kobj_type slab_ktype = {
 | 
					static struct kobj_type slab_ktype = {
 | 
				
			||||||
	.sysfs_ops = &slab_sysfs_ops,
 | 
						.sysfs_ops = &slab_sysfs_ops,
 | 
				
			||||||
 | 
						.release = kmem_cache_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int uevent_filter(struct kset *kset, struct kobject *kobj)
 | 
					static int uevent_filter(struct kset *kset, struct kobject *kobj)
 | 
				
			||||||
| 
						 | 
					@ -5255,7 +5241,7 @@ static int sysfs_slab_add(struct kmem_cache *s)
 | 
				
			||||||
	goto out;
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sysfs_slab_remove(struct kmem_cache *s)
 | 
					void sysfs_slab_remove(struct kmem_cache *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (slab_state < FULL)
 | 
						if (slab_state < FULL)
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue