forked from mirrors/linux
		
	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
	
	 Tejun Heo
						Tejun Heo