diff options
author | Tejun Heo <tj@kernel.org> | 2015-09-18 17:54:23 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2015-09-18 17:54:23 -0400 |
commit | 6f60eade2433cb3a38687d5f8a4f44b92c6c51bf (patch) | |
tree | 0c92e0b5bc6ae4c51c95a5917559e91992acb616 | |
parent | 4df8dc903161c03cd9bff9077d8427fefe808e6d (diff) |
cgroup: generalize obtaining the handles of and notifying cgroup files
cgroup core handles creations and removals of cgroup interface files
as described by cftypes. There are cases where the handle for a given
file instance is necessary, for example, to generate a file modified
event. Currently, this is handled by explicitly matching the callback
method pointer and storing the file handle manually in
cgroup_add_file(). While this simple approach works for cgroup core
files, it can't for controller interface files.
This patch generalizes cgroup interface file handle handling. struct
cgroup_file is defined and each cftype can optionally tell cgroup core
to store the file handle by setting ->file_offset. A file handle
remains accessible as long as the containing css is accessible.
Both "cgroup.procs" and "cgroup.events" are converted to use the new
generic mechanism instead of hooking directly into cgroup_add_file().
Also, cgroup_file_notify() which takes a struct cgroup_file and
generates a file modified event on it is added and replaces explicit
kernfs_notify() invocations.
This generalizes cgroup file handle handling and allows controllers to
generate file modified notifications.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
-rw-r--r-- | include/linux/cgroup-defs.h | 26 | ||||
-rw-r--r-- | include/linux/cgroup.h | 13 | ||||
-rw-r--r-- | kernel/cgroup.c | 26 |
3 files changed, 56 insertions, 9 deletions
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 10d814bcd487..df589a097539 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h | |||
@@ -84,6 +84,17 @@ enum { | |||
84 | }; | 84 | }; |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * cgroup_file is the handle for a file instance created in a cgroup which | ||
88 | * is used, for example, to generate file changed notifications. This can | ||
89 | * be obtained by setting cftype->file_offset. | ||
90 | */ | ||
91 | struct cgroup_file { | ||
92 | /* do not access any fields from outside cgroup core */ | ||
93 | struct list_head node; /* anchored at css->files */ | ||
94 | struct kernfs_node *kn; | ||
95 | }; | ||
96 | |||
97 | /* | ||
87 | * Per-subsystem/per-cgroup state maintained by the system. This is the | 98 | * Per-subsystem/per-cgroup state maintained by the system. This is the |
88 | * fundamental structural building block that controllers deal with. | 99 | * fundamental structural building block that controllers deal with. |
89 | * | 100 | * |
@@ -123,6 +134,9 @@ struct cgroup_subsys_state { | |||
123 | */ | 134 | */ |
124 | u64 serial_nr; | 135 | u64 serial_nr; |
125 | 136 | ||
137 | /* all cgroup_files associated with this css */ | ||
138 | struct list_head files; | ||
139 | |||
126 | /* percpu_ref killing and RCU release */ | 140 | /* percpu_ref killing and RCU release */ |
127 | struct rcu_head rcu_head; | 141 | struct rcu_head rcu_head; |
128 | struct work_struct destroy_work; | 142 | struct work_struct destroy_work; |
@@ -226,8 +240,8 @@ struct cgroup { | |||
226 | int populated_cnt; | 240 | int populated_cnt; |
227 | 241 | ||
228 | struct kernfs_node *kn; /* cgroup kernfs entry */ | 242 | struct kernfs_node *kn; /* cgroup kernfs entry */ |
229 | struct kernfs_node *procs_kn; /* kn for "cgroup.procs" */ | 243 | struct cgroup_file procs_file; /* handle for "cgroup.procs" */ |
230 | struct kernfs_node *events_kn; /* kn for "cgroup.events" */ | 244 | struct cgroup_file events_file; /* handle for "cgroup.events" */ |
231 | 245 | ||
232 | /* | 246 | /* |
233 | * The bitmask of subsystems enabled on the child cgroups. | 247 | * The bitmask of subsystems enabled on the child cgroups. |
@@ -336,6 +350,14 @@ struct cftype { | |||
336 | unsigned int flags; | 350 | unsigned int flags; |
337 | 351 | ||
338 | /* | 352 | /* |
353 | * If non-zero, should contain the offset from the start of css to | ||
354 | * a struct cgroup_file field. cgroup will record the handle of | ||
355 | * the created file into it. The recorded handle can be used as | ||
356 | * long as the containing css remains accessible. | ||
357 | */ | ||
358 | unsigned int file_offset; | ||
359 | |||
360 | /* | ||
339 | * Fields used for internal bookkeeping. Initialized automatically | 361 | * Fields used for internal bookkeeping. Initialized automatically |
340 | * during registration. | 362 | * during registration. |
341 | */ | 363 | */ |
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 355bf2ed8867..fb717f2cba5b 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -490,6 +490,19 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp) | |||
490 | pr_cont_kernfs_path(cgrp->kn); | 490 | pr_cont_kernfs_path(cgrp->kn); |
491 | } | 491 | } |
492 | 492 | ||
493 | /** | ||
494 | * cgroup_file_notify - generate a file modified event for a cgroup_file | ||
495 | * @cfile: target cgroup_file | ||
496 | * | ||
497 | * @cfile must have been obtained by setting cftype->file_offset. | ||
498 | */ | ||
499 | static inline void cgroup_file_notify(struct cgroup_file *cfile) | ||
500 | { | ||
501 | /* might not have been created due to one of the CFTYPE selector flags */ | ||
502 | if (cfile->kn) | ||
503 | kernfs_notify(cfile->kn); | ||
504 | } | ||
505 | |||
493 | #else /* !CONFIG_CGROUPS */ | 506 | #else /* !CONFIG_CGROUPS */ |
494 | 507 | ||
495 | struct cgroup_subsys_state; | 508 | struct cgroup_subsys_state; |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 06c9d1aeea9d..0be276ffe08a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -612,8 +612,8 @@ static void cgroup_update_populated(struct cgroup *cgrp, bool populated) | |||
612 | if (!trigger) | 612 | if (!trigger) |
613 | break; | 613 | break; |
614 | 614 | ||
615 | if (cgrp->events_kn) | 615 | cgroup_file_notify(&cgrp->events_file); |
616 | kernfs_notify(cgrp->events_kn); | 616 | |
617 | cgrp = cgroup_parent(cgrp); | 617 | cgrp = cgroup_parent(cgrp); |
618 | } while (cgrp); | 618 | } while (cgrp); |
619 | } | 619 | } |
@@ -1771,6 +1771,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) | |||
1771 | 1771 | ||
1772 | INIT_LIST_HEAD(&cgrp->self.sibling); | 1772 | INIT_LIST_HEAD(&cgrp->self.sibling); |
1773 | INIT_LIST_HEAD(&cgrp->self.children); | 1773 | INIT_LIST_HEAD(&cgrp->self.children); |
1774 | INIT_LIST_HEAD(&cgrp->self.files); | ||
1774 | INIT_LIST_HEAD(&cgrp->cset_links); | 1775 | INIT_LIST_HEAD(&cgrp->cset_links); |
1775 | INIT_LIST_HEAD(&cgrp->pidlists); | 1776 | INIT_LIST_HEAD(&cgrp->pidlists); |
1776 | mutex_init(&cgrp->pidlist_mutex); | 1777 | mutex_init(&cgrp->pidlist_mutex); |
@@ -2562,7 +2563,7 @@ static int cgroup_procs_write_permission(struct task_struct *task, | |||
2562 | cgrp = cgroup_parent(cgrp); | 2563 | cgrp = cgroup_parent(cgrp); |
2563 | 2564 | ||
2564 | ret = -ENOMEM; | 2565 | ret = -ENOMEM; |
2565 | inode = kernfs_get_inode(sb, cgrp->procs_kn); | 2566 | inode = kernfs_get_inode(sb, cgrp->procs_file.kn); |
2566 | if (inode) { | 2567 | if (inode) { |
2567 | ret = inode_permission(inode, MAY_WRITE); | 2568 | ret = inode_permission(inode, MAY_WRITE); |
2568 | iput(inode); | 2569 | iput(inode); |
@@ -3253,10 +3254,14 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp, | |||
3253 | return ret; | 3254 | return ret; |
3254 | } | 3255 | } |
3255 | 3256 | ||
3256 | if (cft->write == cgroup_procs_write) | 3257 | if (cft->file_offset) { |
3257 | cgrp->procs_kn = kn; | 3258 | struct cgroup_file *cfile = (void *)css + cft->file_offset; |
3258 | else if (cft->seq_show == cgroup_events_show) | 3259 | |
3259 | cgrp->events_kn = kn; | 3260 | kernfs_get(kn); |
3261 | cfile->kn = kn; | ||
3262 | list_add(&cfile->node, &css->files); | ||
3263 | } | ||
3264 | |||
3260 | return 0; | 3265 | return 0; |
3261 | } | 3266 | } |
3262 | 3267 | ||
@@ -4408,6 +4413,7 @@ static int cgroup_clone_children_write(struct cgroup_subsys_state *css, | |||
4408 | static struct cftype cgroup_dfl_base_files[] = { | 4413 | static struct cftype cgroup_dfl_base_files[] = { |
4409 | { | 4414 | { |
4410 | .name = "cgroup.procs", | 4415 | .name = "cgroup.procs", |
4416 | .file_offset = offsetof(struct cgroup, procs_file), | ||
4411 | .seq_start = cgroup_pidlist_start, | 4417 | .seq_start = cgroup_pidlist_start, |
4412 | .seq_next = cgroup_pidlist_next, | 4418 | .seq_next = cgroup_pidlist_next, |
4413 | .seq_stop = cgroup_pidlist_stop, | 4419 | .seq_stop = cgroup_pidlist_stop, |
@@ -4433,6 +4439,7 @@ static struct cftype cgroup_dfl_base_files[] = { | |||
4433 | { | 4439 | { |
4434 | .name = "cgroup.events", | 4440 | .name = "cgroup.events", |
4435 | .flags = CFTYPE_NOT_ON_ROOT, | 4441 | .flags = CFTYPE_NOT_ON_ROOT, |
4442 | .file_offset = offsetof(struct cgroup, events_file), | ||
4436 | .seq_show = cgroup_events_show, | 4443 | .seq_show = cgroup_events_show, |
4437 | }, | 4444 | }, |
4438 | { } /* terminate */ | 4445 | { } /* terminate */ |
@@ -4511,9 +4518,13 @@ static void css_free_work_fn(struct work_struct *work) | |||
4511 | container_of(work, struct cgroup_subsys_state, destroy_work); | 4518 | container_of(work, struct cgroup_subsys_state, destroy_work); |
4512 | struct cgroup_subsys *ss = css->ss; | 4519 | struct cgroup_subsys *ss = css->ss; |
4513 | struct cgroup *cgrp = css->cgroup; | 4520 | struct cgroup *cgrp = css->cgroup; |
4521 | struct cgroup_file *cfile; | ||
4514 | 4522 | ||
4515 | percpu_ref_exit(&css->refcnt); | 4523 | percpu_ref_exit(&css->refcnt); |
4516 | 4524 | ||
4525 | list_for_each_entry(cfile, &css->files, node) | ||
4526 | kernfs_put(cfile->kn); | ||
4527 | |||
4517 | if (ss) { | 4528 | if (ss) { |
4518 | /* css free path */ | 4529 | /* css free path */ |
4519 | int id = css->id; | 4530 | int id = css->id; |
@@ -4618,6 +4629,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css, | |||
4618 | css->ss = ss; | 4629 | css->ss = ss; |
4619 | INIT_LIST_HEAD(&css->sibling); | 4630 | INIT_LIST_HEAD(&css->sibling); |
4620 | INIT_LIST_HEAD(&css->children); | 4631 | INIT_LIST_HEAD(&css->children); |
4632 | INIT_LIST_HEAD(&css->files); | ||
4621 | css->serial_nr = css_serial_nr_next++; | 4633 | css->serial_nr = css_serial_nr_next++; |
4622 | 4634 | ||
4623 | if (cgroup_parent(cgrp)) { | 4635 | if (cgroup_parent(cgrp)) { |