summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2016-12-27 14:49:04 -0500
committerTejun Heo <tj@kernel.org>2016-12-27 14:49:04 -0500
commitb4b90a8e86f2539a028d68077b45e8511dd2adb0 (patch)
tree27bbbcc7d7e18b1f288e982fc01d2b2f631ac5c8 /kernel
parente90cbebc3fa5caea4c8bfeb0d0157a0cee53efc7 (diff)
downloadlinux-b4b90a8e86f2539a028d68077b45e8511dd2adb0.tar.gz
linux-b4b90a8e86f2539a028d68077b45e8511dd2adb0.tar.xz
cgroup: reimplement reading "cgroup.procs" on cgroup v2
On v1, "tasks" and "cgroup.procs" are expected to be sorted which makes the implementation expensive and unnecessarily complicated involving result cache management. v2 doesn't have the sorting requirement, so it can just iterate and print processes one by one. seq_files are either read sequentially or reset to position zero, so the implementation doesn't even need to worry about seeking. This keeps the css_task_iter across multiple read(2) calls and migrations of new processes always append won't miss processes which are newly migrated in before each read(2). Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Acked-by: Zefan Li <lizefan@huawei.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 87167e40c4fa..fd684bfd154d 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4426,6 +4426,60 @@ out_err:
return ret;
}
+static void cgroup_procs_release(struct kernfs_open_file *of)
+{
+ if (of->priv) {
+ css_task_iter_end(of->priv);
+ kfree(of->priv);
+ }
+}
+
+static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct kernfs_open_file *of = s->private;
+ struct css_task_iter *it = of->priv;
+ struct task_struct *task;
+
+ do {
+ task = css_task_iter_next(it);
+ } while (task && !thread_group_leader(task));
+
+ return task;
+}
+
+static void *cgroup_procs_start(struct seq_file *s, loff_t *pos)
+{
+ struct kernfs_open_file *of = s->private;
+ struct cgroup *cgrp = seq_css(s)->cgroup;
+ struct css_task_iter *it = of->priv;
+
+ /*
+ * When a seq_file is seeked, it's always traversed sequentially
+ * from position 0, so we can simply keep iterating on !0 *pos.
+ */
+ if (!it) {
+ if (WARN_ON_ONCE((*pos)++))
+ return ERR_PTR(-EINVAL);
+
+ it = kzalloc(sizeof(*it), GFP_KERNEL);
+ if (!it)
+ return ERR_PTR(-ENOMEM);
+ of->priv = it;
+ css_task_iter_start(&cgrp->self, it);
+ } else if (!(*pos)++) {
+ css_task_iter_end(it);
+ css_task_iter_start(&cgrp->self, it);
+ }
+
+ return cgroup_procs_next(s, NULL, NULL);
+}
+
+static int cgroup_procs_show(struct seq_file *s, void *v)
+{
+ seq_printf(s, "%d\n", task_tgid_vnr(v));
+ return 0;
+}
+
/*
* Stuff for reading the 'tasks'/'procs' files.
*
@@ -4914,11 +4968,10 @@ static struct cftype cgroup_dfl_base_files[] = {
{
.name = "cgroup.procs",
.file_offset = offsetof(struct cgroup, procs_file),
- .seq_start = cgroup_pidlist_start,
- .seq_next = cgroup_pidlist_next,
- .seq_stop = cgroup_pidlist_stop,
- .seq_show = cgroup_pidlist_show,
- .private = CGROUP_FILE_PROCS,
+ .release = cgroup_procs_release,
+ .seq_start = cgroup_procs_start,
+ .seq_next = cgroup_procs_next,
+ .seq_show = cgroup_procs_show,
.write = cgroup_procs_write,
},
{