aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2016-08-10 11:23:44 -0400
committerTejun Heo <tj@kernel.org>2016-08-10 11:23:44 -0400
commit4c737b41de7f4eef2a593803bad1b918dd718b10 (patch)
tree0314164921eaf014c466bc58a57bf21973a63385
parentbb09c8634b1e484b8840fb2384d55739bfcb68bd (diff)
cgroup: make cgroup_path() and friends behave in the style of strlcpy()
cgroup_path() and friends used to format the path from the end and thus the resulting path usually didn't start at the start of the passed in buffer. Also, when the buffer was too small, the partial result was truncated from the head rather than tail and there was no way to tell how long the full path would be. These make the functions less robust and more awkward to use. With recent updates to kernfs_path(), cgroup_path() and friends can be made to behave in strlcpy() style. * cgroup_path(), cgroup_path_ns[_locked]() and task_cgroup_path() now always return the length of the full path. If buffer is too small, it contains nul terminated truncated output. * All users updated accordingly. v2: cgroup_path() usage in kernel/sched/debug.c converted. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Serge Hallyn <serge.hallyn@ubuntu.com> Cc: Peter Zijlstra <peterz@infradead.org>
-rw-r--r--include/linux/blk-cgroup.h11
-rw-r--r--include/linux/cgroup.h16
-rw-r--r--kernel/cgroup.c48
-rw-r--r--kernel/cpuset.c12
-rw-r--r--kernel/sched/debug.c3
5 files changed, 36 insertions, 54 deletions
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h
index 10648e300c93..4e8c215e185c 100644
--- a/include/linux/blk-cgroup.h
+++ b/include/linux/blk-cgroup.h
@@ -343,16 +343,7 @@ static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd)
343 */ 343 */
344static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen) 344static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen)
345{ 345{
346 char *p; 346 return cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
347
348 p = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
349 if (!p) {
350 strncpy(buf, "<unavailable>", buflen);
351 return -ENAMETOOLONG;
352 }
353
354 memmove(buf, p, buf + buflen - p);
355 return 0;
356} 347}
357 348
358/** 349/**
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 5a9abdee43fe..6df36361a492 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -97,7 +97,7 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
97int cgroup_rm_cftypes(struct cftype *cfts); 97int cgroup_rm_cftypes(struct cftype *cfts);
98void cgroup_file_notify(struct cgroup_file *cfile); 98void cgroup_file_notify(struct cgroup_file *cfile);
99 99
100char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); 100int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
101int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); 101int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry);
102int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, 102int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns,
103 struct pid *pid, struct task_struct *tsk); 103 struct pid *pid, struct task_struct *tsk);
@@ -538,15 +538,9 @@ static inline int cgroup_name(struct cgroup *cgrp, char *buf, size_t buflen)
538 return kernfs_name(cgrp->kn, buf, buflen); 538 return kernfs_name(cgrp->kn, buf, buflen);
539} 539}
540 540
541static inline char * __must_check cgroup_path(struct cgroup *cgrp, char *buf, 541static inline int cgroup_path(struct cgroup *cgrp, char *buf, size_t buflen)
542 size_t buflen)
543{ 542{
544 int ret; 543 return kernfs_path(cgrp->kn, buf, buflen);
545
546 ret = kernfs_path(cgrp->kn, buf, buflen);
547 if (ret < 0 || ret >= buflen)
548 return NULL;
549 return buf;
550} 544}
551 545
552static inline void pr_cont_cgroup_name(struct cgroup *cgrp) 546static inline void pr_cont_cgroup_name(struct cgroup *cgrp)
@@ -639,8 +633,8 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
639 struct user_namespace *user_ns, 633 struct user_namespace *user_ns,
640 struct cgroup_namespace *old_ns); 634 struct cgroup_namespace *old_ns);
641 635
642char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, 636int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen,
643 struct cgroup_namespace *ns); 637 struct cgroup_namespace *ns);
644 638
645#else /* !CONFIG_CGROUPS */ 639#else /* !CONFIG_CGROUPS */
646 640
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index d1c51b7f5221..3861161e460f 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2315,22 +2315,18 @@ static struct file_system_type cgroup2_fs_type = {
2315 .fs_flags = FS_USERNS_MOUNT, 2315 .fs_flags = FS_USERNS_MOUNT,
2316}; 2316};
2317 2317
2318static char *cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, 2318static int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
2319 struct cgroup_namespace *ns) 2319 struct cgroup_namespace *ns)
2320{ 2320{
2321 struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root); 2321 struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root);
2322 int ret;
2323 2322
2324 ret = kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen); 2323 return kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen);
2325 if (ret < 0 || ret >= buflen)
2326 return NULL;
2327 return buf;
2328} 2324}
2329 2325
2330char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, 2326int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen,
2331 struct cgroup_namespace *ns) 2327 struct cgroup_namespace *ns)
2332{ 2328{
2333 char *ret; 2329 int ret;
2334 2330
2335 mutex_lock(&cgroup_mutex); 2331 mutex_lock(&cgroup_mutex);
2336 spin_lock_irq(&css_set_lock); 2332 spin_lock_irq(&css_set_lock);
@@ -2357,12 +2353,12 @@ EXPORT_SYMBOL_GPL(cgroup_path_ns);
2357 * 2353 *
2358 * Return value is the same as kernfs_path(). 2354 * Return value is the same as kernfs_path().
2359 */ 2355 */
2360char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) 2356int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
2361{ 2357{
2362 struct cgroup_root *root; 2358 struct cgroup_root *root;
2363 struct cgroup *cgrp; 2359 struct cgroup *cgrp;
2364 int hierarchy_id = 1; 2360 int hierarchy_id = 1;
2365 char *path = NULL; 2361 int ret;
2366 2362
2367 mutex_lock(&cgroup_mutex); 2363 mutex_lock(&cgroup_mutex);
2368 spin_lock_irq(&css_set_lock); 2364 spin_lock_irq(&css_set_lock);
@@ -2371,16 +2367,15 @@ char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
2371 2367
2372 if (root) { 2368 if (root) {
2373 cgrp = task_cgroup_from_root(task, root); 2369 cgrp = task_cgroup_from_root(task, root);
2374 path = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns); 2370 ret = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns);
2375 } else { 2371 } else {
2376 /* if no hierarchy exists, everyone is in "/" */ 2372 /* if no hierarchy exists, everyone is in "/" */
2377 if (strlcpy(buf, "/", buflen) < buflen) 2373 ret = strlcpy(buf, "/", buflen);
2378 path = buf;
2379 } 2374 }
2380 2375
2381 spin_unlock_irq(&css_set_lock); 2376 spin_unlock_irq(&css_set_lock);
2382 mutex_unlock(&cgroup_mutex); 2377 mutex_unlock(&cgroup_mutex);
2383 return path; 2378 return ret;
2384} 2379}
2385EXPORT_SYMBOL_GPL(task_cgroup_path); 2380EXPORT_SYMBOL_GPL(task_cgroup_path);
2386 2381
@@ -5716,7 +5711,7 @@ core_initcall(cgroup_wq_init);
5716int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, 5711int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns,
5717 struct pid *pid, struct task_struct *tsk) 5712 struct pid *pid, struct task_struct *tsk)
5718{ 5713{
5719 char *buf, *path; 5714 char *buf;
5720 int retval; 5715 int retval;
5721 struct cgroup_root *root; 5716 struct cgroup_root *root;
5722 5717
@@ -5759,18 +5754,18 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns,
5759 * " (deleted)" is appended to the cgroup path. 5754 * " (deleted)" is appended to the cgroup path.
5760 */ 5755 */
5761 if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { 5756 if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) {
5762 path = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, 5757 retval = cgroup_path_ns_locked(cgrp, buf, PATH_MAX,
5763 current->nsproxy->cgroup_ns); 5758 current->nsproxy->cgroup_ns);
5764 if (!path) { 5759 if (retval >= PATH_MAX) {
5765 retval = -ENAMETOOLONG; 5760 retval = -ENAMETOOLONG;
5766 goto out_unlock; 5761 goto out_unlock;
5767 } 5762 }
5763
5764 seq_puts(m, buf);
5768 } else { 5765 } else {
5769 path = "/"; 5766 seq_puts(m, "/");
5770 } 5767 }
5771 5768
5772 seq_puts(m, path);
5773
5774 if (cgroup_on_dfl(cgrp) && cgroup_is_dead(cgrp)) 5769 if (cgroup_on_dfl(cgrp) && cgroup_is_dead(cgrp))
5775 seq_puts(m, " (deleted)\n"); 5770 seq_puts(m, " (deleted)\n");
5776 else 5771 else
@@ -6035,8 +6030,9 @@ static void cgroup_release_agent(struct work_struct *work)
6035{ 6030{
6036 struct cgroup *cgrp = 6031 struct cgroup *cgrp =
6037 container_of(work, struct cgroup, release_agent_work); 6032 container_of(work, struct cgroup, release_agent_work);
6038 char *pathbuf = NULL, *agentbuf = NULL, *path; 6033 char *pathbuf = NULL, *agentbuf = NULL;
6039 char *argv[3], *envp[3]; 6034 char *argv[3], *envp[3];
6035 int ret;
6040 6036
6041 mutex_lock(&cgroup_mutex); 6037 mutex_lock(&cgroup_mutex);
6042 6038
@@ -6046,13 +6042,13 @@ static void cgroup_release_agent(struct work_struct *work)
6046 goto out; 6042 goto out;
6047 6043
6048 spin_lock_irq(&css_set_lock); 6044 spin_lock_irq(&css_set_lock);
6049 path = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); 6045 ret = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns);
6050 spin_unlock_irq(&css_set_lock); 6046 spin_unlock_irq(&css_set_lock);
6051 if (!path) 6047 if (ret >= PATH_MAX)
6052 goto out; 6048 goto out;
6053 6049
6054 argv[0] = agentbuf; 6050 argv[0] = agentbuf;
6055 argv[1] = path; 6051 argv[1] = pathbuf;
6056 argv[2] = NULL; 6052 argv[2] = NULL;
6057 6053
6058 /* minimal command environment */ 6054 /* minimal command environment */
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index c7fd2778ed50..793ae6fd96dc 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -2689,7 +2689,7 @@ void __cpuset_memory_pressure_bump(void)
2689int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, 2689int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns,
2690 struct pid *pid, struct task_struct *tsk) 2690 struct pid *pid, struct task_struct *tsk)
2691{ 2691{
2692 char *buf, *p; 2692 char *buf;
2693 struct cgroup_subsys_state *css; 2693 struct cgroup_subsys_state *css;
2694 int retval; 2694 int retval;
2695 2695
@@ -2700,18 +2700,18 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns,
2700 2700
2701 retval = -ENAMETOOLONG; 2701 retval = -ENAMETOOLONG;
2702 css = task_get_css(tsk, cpuset_cgrp_id); 2702 css = task_get_css(tsk, cpuset_cgrp_id);
2703 p = cgroup_path_ns(css->cgroup, buf, PATH_MAX, 2703 retval = cgroup_path_ns(css->cgroup, buf, PATH_MAX,
2704 current->nsproxy->cgroup_ns); 2704 current->nsproxy->cgroup_ns);
2705 css_put(css); 2705 css_put(css);
2706 if (!p) 2706 if (retval >= PATH_MAX)
2707 goto out_free; 2707 goto out_free;
2708 seq_puts(m, p); 2708 seq_puts(m, buf);
2709 seq_putc(m, '\n'); 2709 seq_putc(m, '\n');
2710 retval = 0; 2710 retval = 0;
2711out_free: 2711out_free:
2712 kfree(buf); 2712 kfree(buf);
2713out: 2713out:
2714 return retval; 2714 return 0;
2715} 2715}
2716#endif /* CONFIG_PROC_PID_CPUSET */ 2716#endif /* CONFIG_PROC_PID_CPUSET */
2717 2717
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 2a0a9995256d..23cb609ba4eb 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -410,7 +410,8 @@ static char *task_group_path(struct task_group *tg)
410 if (autogroup_path(tg, group_path, PATH_MAX)) 410 if (autogroup_path(tg, group_path, PATH_MAX))
411 return group_path; 411 return group_path;
412 412
413 return cgroup_path(tg->css.cgroup, group_path, PATH_MAX); 413 cgroup_path(tg->css.cgroup, group_path, PATH_MAX);
414 return group_path;
414} 415}
415#endif 416#endif
416 417