aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-09-18 17:54:23 -0400
committerTejun Heo <tj@kernel.org>2015-09-18 17:54:23 -0400
commit6f60eade2433cb3a38687d5f8a4f44b92c6c51bf (patch)
tree0c92e0b5bc6ae4c51c95a5917559e91992acb616
parent4df8dc903161c03cd9bff9077d8427fefe808e6d (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.h26
-rw-r--r--include/linux/cgroup.h13
-rw-r--r--kernel/cgroup.c26
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 */
91struct 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 */
499static 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
495struct cgroup_subsys_state; 508struct 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,
4408static struct cftype cgroup_dfl_base_files[] = { 4413static 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)) {