mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	cgroup: Implement DEBUG_CGROUP_REF
It's really difficult to debug when cgroup or css refs leak. Let's add a debug option to force the refcnt function to not be inlined so that they can be kprobed for debugging. Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
		
							parent
							
								
									79a818b508
								
							
						
					
					
						commit
						6ab428604f
					
				
					 4 changed files with 117 additions and 85 deletions
				
			
		| 
						 | 
				
			
			@ -309,71 +309,23 @@ void css_task_iter_end(struct css_task_iter *it);
 | 
			
		|||
 * Inline functions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_DEBUG_CGROUP_REF
 | 
			
		||||
void css_get(struct cgroup_subsys_state *css);
 | 
			
		||||
void css_get_many(struct cgroup_subsys_state *css, unsigned int n);
 | 
			
		||||
bool css_tryget(struct cgroup_subsys_state *css);
 | 
			
		||||
bool css_tryget_online(struct cgroup_subsys_state *css);
 | 
			
		||||
void css_put(struct cgroup_subsys_state *css);
 | 
			
		||||
void css_put_many(struct cgroup_subsys_state *css, unsigned int n);
 | 
			
		||||
#else
 | 
			
		||||
#define CGROUP_REF_FN_ATTRS	static inline
 | 
			
		||||
#include <linux/cgroup_refcnt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline u64 cgroup_id(const struct cgroup *cgrp)
 | 
			
		||||
{
 | 
			
		||||
	return cgrp->kn->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_get - obtain a reference on the specified css
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * The caller must already have a reference.
 | 
			
		||||
 */
 | 
			
		||||
static inline void css_get(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_get(&css->refcnt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_get_many - obtain references on the specified css
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 * @n: number of references to get
 | 
			
		||||
 *
 | 
			
		||||
 * The caller must already have a reference.
 | 
			
		||||
 */
 | 
			
		||||
static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_get_many(&css->refcnt, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_tryget - try to obtain a reference on the specified css
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * Obtain a reference on @css unless it already has reached zero and is
 | 
			
		||||
 * being released.  This function doesn't care whether @css is on or
 | 
			
		||||
 * offline.  The caller naturally needs to ensure that @css is accessible
 | 
			
		||||
 * but doesn't have to be holding a reference on it - IOW, RCU protected
 | 
			
		||||
 * access is good enough for this function.  Returns %true if a reference
 | 
			
		||||
 * count was successfully obtained; %false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
static inline bool css_tryget(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		return percpu_ref_tryget(&css->refcnt);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_tryget_online - try to obtain a reference on the specified css if online
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * Obtain a reference on @css if it's online.  The caller naturally needs
 | 
			
		||||
 * to ensure that @css is accessible but doesn't have to be holding a
 | 
			
		||||
 * reference on it - IOW, RCU protected access is good enough for this
 | 
			
		||||
 * function.  Returns %true if a reference count was successfully obtained;
 | 
			
		||||
 * %false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
static inline bool css_tryget_online(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		return percpu_ref_tryget_live(&css->refcnt);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_is_dying - test whether the specified css is dying
 | 
			
		||||
 * @css: target css
 | 
			
		||||
| 
						 | 
				
			
			@ -394,31 +346,6 @@ static inline bool css_is_dying(struct cgroup_subsys_state *css)
 | 
			
		|||
	return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_put - put a css reference
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * Put a reference obtained via css_get() and css_tryget_online().
 | 
			
		||||
 */
 | 
			
		||||
static inline void css_put(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_put(&css->refcnt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_put_many - put css references
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 * @n: number of references to put
 | 
			
		||||
 *
 | 
			
		||||
 * Put references obtained via css_get() and css_tryget_online().
 | 
			
		||||
 */
 | 
			
		||||
static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_put_many(&css->refcnt, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void cgroup_get(struct cgroup *cgrp)
 | 
			
		||||
{
 | 
			
		||||
	css_get(&cgrp->self);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										90
									
								
								include/linux/cgroup_refcnt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								include/linux/cgroup_refcnt.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
/**
 | 
			
		||||
 * css_get - obtain a reference on the specified css
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * The caller must already have a reference.
 | 
			
		||||
 */
 | 
			
		||||
CGROUP_REF_FN_ATTRS
 | 
			
		||||
void css_get(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_get(&css->refcnt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_get_many - obtain references on the specified css
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 * @n: number of references to get
 | 
			
		||||
 *
 | 
			
		||||
 * The caller must already have a reference.
 | 
			
		||||
 */
 | 
			
		||||
CGROUP_REF_FN_ATTRS
 | 
			
		||||
void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_get_many(&css->refcnt, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_tryget - try to obtain a reference on the specified css
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * Obtain a reference on @css unless it already has reached zero and is
 | 
			
		||||
 * being released.  This function doesn't care whether @css is on or
 | 
			
		||||
 * offline.  The caller naturally needs to ensure that @css is accessible
 | 
			
		||||
 * but doesn't have to be holding a reference on it - IOW, RCU protected
 | 
			
		||||
 * access is good enough for this function.  Returns %true if a reference
 | 
			
		||||
 * count was successfully obtained; %false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
CGROUP_REF_FN_ATTRS
 | 
			
		||||
bool css_tryget(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		return percpu_ref_tryget(&css->refcnt);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_tryget_online - try to obtain a reference on the specified css if online
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * Obtain a reference on @css if it's online.  The caller naturally needs
 | 
			
		||||
 * to ensure that @css is accessible but doesn't have to be holding a
 | 
			
		||||
 * reference on it - IOW, RCU protected access is good enough for this
 | 
			
		||||
 * function.  Returns %true if a reference count was successfully obtained;
 | 
			
		||||
 * %false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
CGROUP_REF_FN_ATTRS
 | 
			
		||||
bool css_tryget_online(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		return percpu_ref_tryget_live(&css->refcnt);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_put - put a css reference
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 *
 | 
			
		||||
 * Put a reference obtained via css_get() and css_tryget_online().
 | 
			
		||||
 */
 | 
			
		||||
CGROUP_REF_FN_ATTRS
 | 
			
		||||
void css_put(struct cgroup_subsys_state *css)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_put(&css->refcnt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * css_put_many - put css references
 | 
			
		||||
 * @css: target css
 | 
			
		||||
 * @n: number of references to put
 | 
			
		||||
 *
 | 
			
		||||
 * Put references obtained via css_get() and css_tryget_online().
 | 
			
		||||
 */
 | 
			
		||||
CGROUP_REF_FN_ATTRS
 | 
			
		||||
void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	if (!(css->flags & CSS_NO_REF))
 | 
			
		||||
		percpu_ref_put_many(&css->refcnt, n);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -248,6 +248,11 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css,
 | 
			
		|||
			      struct cgroup *cgrp, struct cftype cfts[],
 | 
			
		||||
			      bool is_add);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_DEBUG_CGROUP_REF
 | 
			
		||||
#define CGROUP_REF_FN_ATTRS	noinline
 | 
			
		||||
#include <linux/cgroup_refcnt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * cgroup_ssid_enabled - cgroup subsys enabled test by subsys ID
 | 
			
		||||
 * @ssid: subsys ID of interest
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1701,6 +1701,16 @@ config LATENCYTOP
 | 
			
		|||
	  Enable this option if you want to use the LatencyTOP tool
 | 
			
		||||
	  to find out which userspace is blocking on what kernel operations.
 | 
			
		||||
 | 
			
		||||
config DEBUG_CGROUP_REF
 | 
			
		||||
	bool "Disable inlining of cgroup css reference count functions"
 | 
			
		||||
	depends on DEBUG_KERNEL
 | 
			
		||||
	depends on CGROUPS
 | 
			
		||||
	depends on KPROBES
 | 
			
		||||
	default n
 | 
			
		||||
	help
 | 
			
		||||
	  Force cgroup css reference count functions to not be inlined so
 | 
			
		||||
	  that they can be kprobed for debugging.
 | 
			
		||||
 | 
			
		||||
source "kernel/trace/Kconfig"
 | 
			
		||||
 | 
			
		||||
config PROVIDE_OHCI1394_DMA_INIT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue