Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

+117 -85
+12 -85
include/linux/cgroup.h
··· 309 309 * Inline functions. 310 310 */ 311 311 312 + #ifdef CONFIG_DEBUG_CGROUP_REF 313 + void css_get(struct cgroup_subsys_state *css); 314 + void css_get_many(struct cgroup_subsys_state *css, unsigned int n); 315 + bool css_tryget(struct cgroup_subsys_state *css); 316 + bool css_tryget_online(struct cgroup_subsys_state *css); 317 + void css_put(struct cgroup_subsys_state *css); 318 + void css_put_many(struct cgroup_subsys_state *css, unsigned int n); 319 + #else 320 + #define CGROUP_REF_FN_ATTRS static inline 321 + #include <linux/cgroup_refcnt.h> 322 + #endif 323 + 312 324 static inline u64 cgroup_id(const struct cgroup *cgrp) 313 325 { 314 326 return cgrp->kn->id; 315 - } 316 - 317 - /** 318 - * css_get - obtain a reference on the specified css 319 - * @css: target css 320 - * 321 - * The caller must already have a reference. 322 - */ 323 - static inline void css_get(struct cgroup_subsys_state *css) 324 - { 325 - if (!(css->flags & CSS_NO_REF)) 326 - percpu_ref_get(&css->refcnt); 327 - } 328 - 329 - /** 330 - * css_get_many - obtain references on the specified css 331 - * @css: target css 332 - * @n: number of references to get 333 - * 334 - * The caller must already have a reference. 335 - */ 336 - static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n) 337 - { 338 - if (!(css->flags & CSS_NO_REF)) 339 - percpu_ref_get_many(&css->refcnt, n); 340 - } 341 - 342 - /** 343 - * css_tryget - try to obtain a reference on the specified css 344 - * @css: target css 345 - * 346 - * Obtain a reference on @css unless it already has reached zero and is 347 - * being released. This function doesn't care whether @css is on or 348 - * offline. The caller naturally needs to ensure that @css is accessible 349 - * but doesn't have to be holding a reference on it - IOW, RCU protected 350 - * access is good enough for this function. Returns %true if a reference 351 - * count was successfully obtained; %false otherwise. 352 - */ 353 - static inline bool css_tryget(struct cgroup_subsys_state *css) 354 - { 355 - if (!(css->flags & CSS_NO_REF)) 356 - return percpu_ref_tryget(&css->refcnt); 357 - return true; 358 - } 359 - 360 - /** 361 - * css_tryget_online - try to obtain a reference on the specified css if online 362 - * @css: target css 363 - * 364 - * Obtain a reference on @css if it's online. The caller naturally needs 365 - * to ensure that @css is accessible but doesn't have to be holding a 366 - * reference on it - IOW, RCU protected access is good enough for this 367 - * function. Returns %true if a reference count was successfully obtained; 368 - * %false otherwise. 369 - */ 370 - static inline bool css_tryget_online(struct cgroup_subsys_state *css) 371 - { 372 - if (!(css->flags & CSS_NO_REF)) 373 - return percpu_ref_tryget_live(&css->refcnt); 374 - return true; 375 327 } 376 328 377 329 /** ··· 344 392 static inline bool css_is_dying(struct cgroup_subsys_state *css) 345 393 { 346 394 return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt); 347 - } 348 - 349 - /** 350 - * css_put - put a css reference 351 - * @css: target css 352 - * 353 - * Put a reference obtained via css_get() and css_tryget_online(). 354 - */ 355 - static inline void css_put(struct cgroup_subsys_state *css) 356 - { 357 - if (!(css->flags & CSS_NO_REF)) 358 - percpu_ref_put(&css->refcnt); 359 - } 360 - 361 - /** 362 - * css_put_many - put css references 363 - * @css: target css 364 - * @n: number of references to put 365 - * 366 - * Put references obtained via css_get() and css_tryget_online(). 367 - */ 368 - static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n) 369 - { 370 - if (!(css->flags & CSS_NO_REF)) 371 - percpu_ref_put_many(&css->refcnt, n); 372 395 } 373 396 374 397 static inline void cgroup_get(struct cgroup *cgrp)
+90
include/linux/cgroup_refcnt.h
··· 1 + /** 2 + * css_get - obtain a reference on the specified css 3 + * @css: target css 4 + * 5 + * The caller must already have a reference. 6 + */ 7 + CGROUP_REF_FN_ATTRS 8 + void css_get(struct cgroup_subsys_state *css) 9 + { 10 + if (!(css->flags & CSS_NO_REF)) 11 + percpu_ref_get(&css->refcnt); 12 + } 13 + 14 + /** 15 + * css_get_many - obtain references on the specified css 16 + * @css: target css 17 + * @n: number of references to get 18 + * 19 + * The caller must already have a reference. 20 + */ 21 + CGROUP_REF_FN_ATTRS 22 + void css_get_many(struct cgroup_subsys_state *css, unsigned int n) 23 + { 24 + if (!(css->flags & CSS_NO_REF)) 25 + percpu_ref_get_many(&css->refcnt, n); 26 + } 27 + 28 + /** 29 + * css_tryget - try to obtain a reference on the specified css 30 + * @css: target css 31 + * 32 + * Obtain a reference on @css unless it already has reached zero and is 33 + * being released. This function doesn't care whether @css is on or 34 + * offline. The caller naturally needs to ensure that @css is accessible 35 + * but doesn't have to be holding a reference on it - IOW, RCU protected 36 + * access is good enough for this function. Returns %true if a reference 37 + * count was successfully obtained; %false otherwise. 38 + */ 39 + CGROUP_REF_FN_ATTRS 40 + bool css_tryget(struct cgroup_subsys_state *css) 41 + { 42 + if (!(css->flags & CSS_NO_REF)) 43 + return percpu_ref_tryget(&css->refcnt); 44 + return true; 45 + } 46 + 47 + /** 48 + * css_tryget_online - try to obtain a reference on the specified css if online 49 + * @css: target css 50 + * 51 + * Obtain a reference on @css if it's online. The caller naturally needs 52 + * to ensure that @css is accessible but doesn't have to be holding a 53 + * reference on it - IOW, RCU protected access is good enough for this 54 + * function. Returns %true if a reference count was successfully obtained; 55 + * %false otherwise. 56 + */ 57 + CGROUP_REF_FN_ATTRS 58 + bool css_tryget_online(struct cgroup_subsys_state *css) 59 + { 60 + if (!(css->flags & CSS_NO_REF)) 61 + return percpu_ref_tryget_live(&css->refcnt); 62 + return true; 63 + } 64 + 65 + /** 66 + * css_put - put a css reference 67 + * @css: target css 68 + * 69 + * Put a reference obtained via css_get() and css_tryget_online(). 70 + */ 71 + CGROUP_REF_FN_ATTRS 72 + void css_put(struct cgroup_subsys_state *css) 73 + { 74 + if (!(css->flags & CSS_NO_REF)) 75 + percpu_ref_put(&css->refcnt); 76 + } 77 + 78 + /** 79 + * css_put_many - put css references 80 + * @css: target css 81 + * @n: number of references to put 82 + * 83 + * Put references obtained via css_get() and css_tryget_online(). 84 + */ 85 + CGROUP_REF_FN_ATTRS 86 + void css_put_many(struct cgroup_subsys_state *css, unsigned int n) 87 + { 88 + if (!(css->flags & CSS_NO_REF)) 89 + percpu_ref_put_many(&css->refcnt, n); 90 + }
+5
kernel/cgroup/cgroup.c
··· 248 248 struct cgroup *cgrp, struct cftype cfts[], 249 249 bool is_add); 250 250 251 + #ifdef CONFIG_DEBUG_CGROUP_REF 252 + #define CGROUP_REF_FN_ATTRS noinline 253 + #include <linux/cgroup_refcnt.h> 254 + #endif 255 + 251 256 /** 252 257 * cgroup_ssid_enabled - cgroup subsys enabled test by subsys ID 253 258 * @ssid: subsys ID of interest
+10
lib/Kconfig.debug
··· 1701 1701 Enable this option if you want to use the LatencyTOP tool 1702 1702 to find out which userspace is blocking on what kernel operations. 1703 1703 1704 + config DEBUG_CGROUP_REF 1705 + bool "Disable inlining of cgroup css reference count functions" 1706 + depends on DEBUG_KERNEL 1707 + depends on CGROUPS 1708 + depends on KPROBES 1709 + default n 1710 + help 1711 + Force cgroup css reference count functions to not be inlined so 1712 + that they can be kprobed for debugging. 1713 + 1704 1714 source "kernel/trace/Kconfig" 1705 1715 1706 1716 config PROVIDE_OHCI1394_DMA_INIT