aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-04-02 19:57:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:04:53 -0400
commit38460b48d06440de46b34cb778bd6c4855030754 (patch)
tree8f3362a446b5b03879f715c3f7279e70842bcca9 /include
parent313e924c0852943e67335fad9d2608701f0dfe8e (diff)
cgroup: CSS ID support
Patch for Per-CSS(Cgroup Subsys State) ID and private hierarchy code. This patch attaches unique ID to each css and provides following. - css_lookup(subsys, id) returns pointer to struct cgroup_subysys_state of id. - css_get_next(subsys, id, rootid, depth, foundid) returns the next css under "root" by scanning When cgroup_subsys->use_id is set, an id for css is maintained. The cgroup framework only parepares - css_id of root css for subsys - id is automatically attached at creation of css. - id is *not* freed automatically. Because the cgroup framework don't know lifetime of cgroup_subsys_state. free_css_id() function is provided. This must be called by subsys. There are several reasons to develop this. - Saving space .... For example, memcg's swap_cgroup is array of pointers to cgroup. But it is not necessary to be very fast. By replacing pointers(8bytes per ent) to ID (2byes per ent), we can reduce much amount of memory usage. - Scanning without lock. CSS_ID provides "scan id under this ROOT" function. By this, scanning css under root can be written without locks. ex) do { rcu_read_lock(); next = cgroup_get_next(subsys, id, root, &found); /* check sanity of next here */ css_tryget(); rcu_read_unlock(); id = found + 1 } while(...) Characteristics: - Each css has unique ID under subsys. - Lifetime of ID is controlled by subsys. - css ID contains "ID" and "Depth in hierarchy" and stack of hierarchy - Allowed ID is 1-65535, ID 0 is UNUSED ID. Design Choices: - scan-by-ID v.s. scan-by-tree-walk. As /proc's pid scan does, scan-by-ID is robust when scanning is done by following kind of routine. scan -> rest a while(release a lock) -> conitunue from interrupted memcg's hierarchical reclaim does this. - When subsys->use_id is set, # of css in the system is limited to 65535. [bharata@linux.vnet.ibm.com: remove rcu_read_lock() from css_get_next()] Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Acked-by: Paul Menage <menage@google.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: Bharata B Rao <bharata@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/cgroup.h50
-rw-r--r--include/linux/idr.h1
2 files changed, 51 insertions, 0 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 788c4964c142..9a23bb098205 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -15,6 +15,7 @@
15#include <linux/cgroupstats.h> 15#include <linux/cgroupstats.h>
16#include <linux/prio_heap.h> 16#include <linux/prio_heap.h>
17#include <linux/rwsem.h> 17#include <linux/rwsem.h>
18#include <linux/idr.h>
18 19
19#ifdef CONFIG_CGROUPS 20#ifdef CONFIG_CGROUPS
20 21
@@ -22,6 +23,7 @@ struct cgroupfs_root;
22struct cgroup_subsys; 23struct cgroup_subsys;
23struct inode; 24struct inode;
24struct cgroup; 25struct cgroup;
26struct css_id;
25 27
26extern int cgroup_init_early(void); 28extern int cgroup_init_early(void);
27extern int cgroup_init(void); 29extern int cgroup_init(void);
@@ -63,6 +65,8 @@ struct cgroup_subsys_state {
63 atomic_t refcnt; 65 atomic_t refcnt;
64 66
65 unsigned long flags; 67 unsigned long flags;
68 /* ID for this css, if possible */
69 struct css_id *id;
66}; 70};
67 71
68/* bits in struct cgroup_subsys_state flags field */ 72/* bits in struct cgroup_subsys_state flags field */
@@ -373,6 +377,11 @@ struct cgroup_subsys {
373 int active; 377 int active;
374 int disabled; 378 int disabled;
375 int early_init; 379 int early_init;
380 /*
381 * True if this subsys uses ID. ID is not available before cgroup_init()
382 * (not available in early_init time.)
383 */
384 bool use_id;
376#define MAX_CGROUP_TYPE_NAMELEN 32 385#define MAX_CGROUP_TYPE_NAMELEN 32
377 const char *name; 386 const char *name;
378 387
@@ -395,6 +404,9 @@ struct cgroup_subsys {
395 */ 404 */
396 struct cgroupfs_root *root; 405 struct cgroupfs_root *root;
397 struct list_head sibling; 406 struct list_head sibling;
407 /* used when use_id == true */
408 struct idr idr;
409 spinlock_t id_lock;
398}; 410};
399 411
400#define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; 412#define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys;
@@ -450,6 +462,44 @@ void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
450int cgroup_scan_tasks(struct cgroup_scanner *scan); 462int cgroup_scan_tasks(struct cgroup_scanner *scan);
451int cgroup_attach_task(struct cgroup *, struct task_struct *); 463int cgroup_attach_task(struct cgroup *, struct task_struct *);
452 464
465/*
466 * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
467 * if cgroup_subsys.use_id == true. It can be used for looking up and scanning.
468 * CSS ID is assigned at cgroup allocation (create) automatically
469 * and removed when subsys calls free_css_id() function. This is because
470 * the lifetime of cgroup_subsys_state is subsys's matter.
471 *
472 * Looking up and scanning function should be called under rcu_read_lock().
473 * Taking cgroup_mutex()/hierarchy_mutex() is not necessary for following calls.
474 * But the css returned by this routine can be "not populated yet" or "being
475 * destroyed". The caller should check css and cgroup's status.
476 */
477
478/*
479 * Typically Called at ->destroy(), or somewhere the subsys frees
480 * cgroup_subsys_state.
481 */
482void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css);
483
484/* Find a cgroup_subsys_state which has given ID */
485
486struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id);
487
488/*
489 * Get a cgroup whose id is greater than or equal to id under tree of root.
490 * Returning a cgroup_subsys_state or NULL.
491 */
492struct cgroup_subsys_state *css_get_next(struct cgroup_subsys *ss, int id,
493 struct cgroup_subsys_state *root, int *foundid);
494
495/* Returns true if root is ancestor of cg */
496bool css_is_ancestor(struct cgroup_subsys_state *cg,
497 struct cgroup_subsys_state *root);
498
499/* Get id and depth of css */
500unsigned short css_id(struct cgroup_subsys_state *css);
501unsigned short css_depth(struct cgroup_subsys_state *css);
502
453#else /* !CONFIG_CGROUPS */ 503#else /* !CONFIG_CGROUPS */
454 504
455static inline int cgroup_init_early(void) { return 0; } 505static inline int cgroup_init_early(void) { return 0; }
diff --git a/include/linux/idr.h b/include/linux/idr.h
index dd846df8cd32..e968db71e33a 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -106,6 +106,7 @@ int idr_get_new(struct idr *idp, void *ptr, int *id);
106int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); 106int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
107int idr_for_each(struct idr *idp, 107int idr_for_each(struct idr *idp,
108 int (*fn)(int id, void *p, void *data), void *data); 108 int (*fn)(int id, void *p, void *data), void *data);
109void *idr_get_next(struct idr *idp, int *nextid);
109void *idr_replace(struct idr *idp, void *ptr, int id); 110void *idr_replace(struct idr *idp, void *ptr, int id);
110void idr_remove(struct idr *idp, int id); 111void idr_remove(struct idr *idp, int id);
111void idr_remove_all(struct idr *idp); 112void idr_remove_all(struct idr *idp);