diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-14 15:18:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-14 15:18:50 -0400 |
commit | f34d3606f76a8121b9d4940d2dd436bebeb2f9d7 (patch) | |
tree | 61a9deb6a950568df274580fbbd44a7015af9f7c | |
parent | b6daa51b9a6a02a644dcf6b880fd50c1f70ec07f (diff) | |
parent | bbb427e342495df1cda10051d0566388697499c0 (diff) |
Merge branch 'for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup updates from Tejun Heo:
- tracepoints for basic cgroup management operations added
- kernfs and cgroup path formatting functions updated to behave in the
style of strlcpy()
- non-critical bug fixes
* 'for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
blkcg: Unlock blkcg_pol_mutex only once when cpd == NULL
cgroup: fix error handling regressions in proc_cgroup_show() and cgroup_release_agent()
cpuset: fix error handling regression in proc_cpuset_show()
cgroup: add tracepoints for basic operations
cgroup: make cgroup_path() and friends behave in the style of strlcpy()
kernfs: remove kernfs_path_len()
kernfs: make kernfs_path*() behave in the style of strlcpy()
kernfs: add dummy implementation of kernfs_path_from_node()
-rw-r--r-- | block/blk-cgroup.c | 4 | ||||
-rw-r--r-- | fs/kernfs/dir.c | 84 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 6 | ||||
-rw-r--r-- | include/linux/blk-cgroup.h | 11 | ||||
-rw-r--r-- | include/linux/cgroup.h | 9 | ||||
-rw-r--r-- | include/linux/kernfs.h | 28 | ||||
-rw-r--r-- | include/trace/events/cgroup.h | 163 | ||||
-rw-r--r-- | kernel/cgroup.c | 75 | ||||
-rw-r--r-- | kernel/cpuset.c | 13 | ||||
-rw-r--r-- | kernel/sched/debug.c | 3 |
10 files changed, 266 insertions, 130 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index dd38e5ced4a3..b08ccbb9393a 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -1340,10 +1340,8 @@ int blkcg_policy_register(struct blkcg_policy *pol) | |||
1340 | struct blkcg_policy_data *cpd; | 1340 | struct blkcg_policy_data *cpd; |
1341 | 1341 | ||
1342 | cpd = pol->cpd_alloc_fn(GFP_KERNEL); | 1342 | cpd = pol->cpd_alloc_fn(GFP_KERNEL); |
1343 | if (!cpd) { | 1343 | if (!cpd) |
1344 | mutex_unlock(&blkcg_pol_mutex); | ||
1345 | goto err_free_cpds; | 1344 | goto err_free_cpds; |
1346 | } | ||
1347 | 1345 | ||
1348 | blkcg->cpd[pol->plid] = cpd; | 1346 | blkcg->cpd[pol->plid] = cpd; |
1349 | cpd->blkcg = blkcg; | 1347 | cpd->blkcg = blkcg; |
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index dcd96aac02f5..cf4c636ff4da 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c | |||
@@ -110,8 +110,9 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a, | |||
110 | * kn_to: /n1/n2/n3 [depth=3] | 110 | * kn_to: /n1/n2/n3 [depth=3] |
111 | * result: /../.. | 111 | * result: /../.. |
112 | * | 112 | * |
113 | * return value: length of the string. If greater than buflen, | 113 | * Returns the length of the full path. If the full length is equal to or |
114 | * then contents of buf are undefined. On error, -1 is returned. | 114 | * greater than @buflen, @buf contains the truncated path with the trailing |
115 | * '\0'. On error, -errno is returned. | ||
115 | */ | 116 | */ |
116 | static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, | 117 | static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, |
117 | struct kernfs_node *kn_from, | 118 | struct kernfs_node *kn_from, |
@@ -119,9 +120,8 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, | |||
119 | { | 120 | { |
120 | struct kernfs_node *kn, *common; | 121 | struct kernfs_node *kn, *common; |
121 | const char parent_str[] = "/.."; | 122 | const char parent_str[] = "/.."; |
122 | size_t depth_from, depth_to, len = 0, nlen = 0; | 123 | size_t depth_from, depth_to, len = 0; |
123 | char *p; | 124 | int i, j; |
124 | int i; | ||
125 | 125 | ||
126 | if (!kn_from) | 126 | if (!kn_from) |
127 | kn_from = kernfs_root(kn_to)->kn; | 127 | kn_from = kernfs_root(kn_to)->kn; |
@@ -131,7 +131,7 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, | |||
131 | 131 | ||
132 | common = kernfs_common_ancestor(kn_from, kn_to); | 132 | common = kernfs_common_ancestor(kn_from, kn_to); |
133 | if (WARN_ON(!common)) | 133 | if (WARN_ON(!common)) |
134 | return -1; | 134 | return -EINVAL; |
135 | 135 | ||
136 | depth_to = kernfs_depth(common, kn_to); | 136 | depth_to = kernfs_depth(common, kn_to); |
137 | depth_from = kernfs_depth(common, kn_from); | 137 | depth_from = kernfs_depth(common, kn_from); |
@@ -144,22 +144,16 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, | |||
144 | len < buflen ? buflen - len : 0); | 144 | len < buflen ? buflen - len : 0); |
145 | 145 | ||
146 | /* Calculate how many bytes we need for the rest */ | 146 | /* Calculate how many bytes we need for the rest */ |
147 | for (kn = kn_to; kn != common; kn = kn->parent) | 147 | for (i = depth_to - 1; i >= 0; i--) { |
148 | nlen += strlen(kn->name) + 1; | 148 | for (kn = kn_to, j = 0; j < i; j++) |
149 | 149 | kn = kn->parent; | |
150 | if (len + nlen >= buflen) | 150 | len += strlcpy(buf + len, "/", |
151 | return len + nlen; | 151 | len < buflen ? buflen - len : 0); |
152 | 152 | len += strlcpy(buf + len, kn->name, | |
153 | p = buf + len + nlen; | 153 | len < buflen ? buflen - len : 0); |
154 | *p = '\0'; | ||
155 | for (kn = kn_to; kn != common; kn = kn->parent) { | ||
156 | size_t tmp = strlen(kn->name); | ||
157 | p -= tmp; | ||
158 | memcpy(p, kn->name, tmp); | ||
159 | *(--p) = '/'; | ||
160 | } | 154 | } |
161 | 155 | ||
162 | return len + nlen; | 156 | return len; |
163 | } | 157 | } |
164 | 158 | ||
165 | /** | 159 | /** |
@@ -186,29 +180,6 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) | |||
186 | } | 180 | } |
187 | 181 | ||
188 | /** | 182 | /** |
189 | * kernfs_path_len - determine the length of the full path of a given node | ||
190 | * @kn: kernfs_node of interest | ||
191 | * | ||
192 | * The returned length doesn't include the space for the terminating '\0'. | ||
193 | */ | ||
194 | size_t kernfs_path_len(struct kernfs_node *kn) | ||
195 | { | ||
196 | size_t len = 0; | ||
197 | unsigned long flags; | ||
198 | |||
199 | spin_lock_irqsave(&kernfs_rename_lock, flags); | ||
200 | |||
201 | do { | ||
202 | len += strlen(kn->name) + 1; | ||
203 | kn = kn->parent; | ||
204 | } while (kn && kn->parent); | ||
205 | |||
206 | spin_unlock_irqrestore(&kernfs_rename_lock, flags); | ||
207 | |||
208 | return len; | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * kernfs_path_from_node - build path of node @to relative to @from. | 183 | * kernfs_path_from_node - build path of node @to relative to @from. |
213 | * @from: parent kernfs_node relative to which we need to build the path | 184 | * @from: parent kernfs_node relative to which we need to build the path |
214 | * @to: kernfs_node of interest | 185 | * @to: kernfs_node of interest |
@@ -220,8 +191,9 @@ size_t kernfs_path_len(struct kernfs_node *kn) | |||
220 | * path (which includes '..'s) as needed to reach from @from to @to is | 191 | * path (which includes '..'s) as needed to reach from @from to @to is |
221 | * returned. | 192 | * returned. |
222 | * | 193 | * |
223 | * If @buf isn't long enough, the return value will be greater than @buflen | 194 | * Returns the length of the full path. If the full length is equal to or |
224 | * and @buf contents are undefined. | 195 | * greater than @buflen, @buf contains the truncated path with the trailing |
196 | * '\0'. On error, -errno is returned. | ||
225 | */ | 197 | */ |
226 | int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, | 198 | int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, |
227 | char *buf, size_t buflen) | 199 | char *buf, size_t buflen) |
@@ -237,28 +209,6 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, | |||
237 | EXPORT_SYMBOL_GPL(kernfs_path_from_node); | 209 | EXPORT_SYMBOL_GPL(kernfs_path_from_node); |
238 | 210 | ||
239 | /** | 211 | /** |
240 | * kernfs_path - build full path of a given node | ||
241 | * @kn: kernfs_node of interest | ||
242 | * @buf: buffer to copy @kn's name into | ||
243 | * @buflen: size of @buf | ||
244 | * | ||
245 | * Builds and returns the full path of @kn in @buf of @buflen bytes. The | ||
246 | * path is built from the end of @buf so the returned pointer usually | ||
247 | * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated | ||
248 | * and %NULL is returned. | ||
249 | */ | ||
250 | char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) | ||
251 | { | ||
252 | int ret; | ||
253 | |||
254 | ret = kernfs_path_from_node(kn, NULL, buf, buflen); | ||
255 | if (ret < 0 || ret >= buflen) | ||
256 | return NULL; | ||
257 | return buf; | ||
258 | } | ||
259 | EXPORT_SYMBOL_GPL(kernfs_path); | ||
260 | |||
261 | /** | ||
262 | * pr_cont_kernfs_name - pr_cont name of a kernfs_node | 212 | * pr_cont_kernfs_name - pr_cont name of a kernfs_node |
263 | * @kn: kernfs_node of interest | 213 | * @kn: kernfs_node of interest |
264 | * | 214 | * |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 94374e435025..2b67bda2021b 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -21,14 +21,14 @@ DEFINE_SPINLOCK(sysfs_symlink_target_lock); | |||
21 | 21 | ||
22 | void sysfs_warn_dup(struct kernfs_node *parent, const char *name) | 22 | void sysfs_warn_dup(struct kernfs_node *parent, const char *name) |
23 | { | 23 | { |
24 | char *buf, *path = NULL; | 24 | char *buf; |
25 | 25 | ||
26 | buf = kzalloc(PATH_MAX, GFP_KERNEL); | 26 | buf = kzalloc(PATH_MAX, GFP_KERNEL); |
27 | if (buf) | 27 | if (buf) |
28 | path = kernfs_path(parent, buf, PATH_MAX); | 28 | kernfs_path(parent, buf, PATH_MAX); |
29 | 29 | ||
30 | WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s/%s'\n", | 30 | WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s/%s'\n", |
31 | path, name); | 31 | buf, name); |
32 | 32 | ||
33 | kfree(buf); | 33 | kfree(buf); |
34 | } | 34 | } |
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index cbdbf34de5b6..3bf5d33800ab 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 | */ |
344 | static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen) | 344 | static 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 440a72164a11..c83c23f0577b 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); | |||
97 | int cgroup_rm_cftypes(struct cftype *cfts); | 97 | int cgroup_rm_cftypes(struct cftype *cfts); |
98 | void cgroup_file_notify(struct cgroup_file *cfile); | 98 | void cgroup_file_notify(struct cgroup_file *cfile); |
99 | 99 | ||
100 | char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); | 100 | int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); |
101 | int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); | 101 | int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); |
102 | int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, | 102 | int 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); |
@@ -555,8 +555,7 @@ static inline int cgroup_name(struct cgroup *cgrp, char *buf, size_t buflen) | |||
555 | return kernfs_name(cgrp->kn, buf, buflen); | 555 | return kernfs_name(cgrp->kn, buf, buflen); |
556 | } | 556 | } |
557 | 557 | ||
558 | static inline char * __must_check cgroup_path(struct cgroup *cgrp, char *buf, | 558 | static inline int cgroup_path(struct cgroup *cgrp, char *buf, size_t buflen) |
559 | size_t buflen) | ||
560 | { | 559 | { |
561 | return kernfs_path(cgrp->kn, buf, buflen); | 560 | return kernfs_path(cgrp->kn, buf, buflen); |
562 | } | 561 | } |
@@ -658,8 +657,8 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, | |||
658 | struct user_namespace *user_ns, | 657 | struct user_namespace *user_ns, |
659 | struct cgroup_namespace *old_ns); | 658 | struct cgroup_namespace *old_ns); |
660 | 659 | ||
661 | char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, | 660 | int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, |
662 | struct cgroup_namespace *ns); | 661 | struct cgroup_namespace *ns); |
663 | 662 | ||
664 | #else /* !CONFIG_CGROUPS */ | 663 | #else /* !CONFIG_CGROUPS */ |
665 | 664 | ||
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 96356ef012de..7056238fd9f5 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
@@ -269,10 +269,8 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) | |||
269 | } | 269 | } |
270 | 270 | ||
271 | int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); | 271 | int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); |
272 | size_t kernfs_path_len(struct kernfs_node *kn); | ||
273 | int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, | 272 | int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, |
274 | char *buf, size_t buflen); | 273 | char *buf, size_t buflen); |
275 | char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen); | ||
276 | void pr_cont_kernfs_name(struct kernfs_node *kn); | 274 | void pr_cont_kernfs_name(struct kernfs_node *kn); |
277 | void pr_cont_kernfs_path(struct kernfs_node *kn); | 275 | void pr_cont_kernfs_path(struct kernfs_node *kn); |
278 | struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); | 276 | struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); |
@@ -341,12 +339,10 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) | |||
341 | static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) | 339 | static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) |
342 | { return -ENOSYS; } | 340 | { return -ENOSYS; } |
343 | 341 | ||
344 | static inline size_t kernfs_path_len(struct kernfs_node *kn) | 342 | static inline int kernfs_path_from_node(struct kernfs_node *root_kn, |
345 | { return 0; } | 343 | struct kernfs_node *kn, |
346 | 344 | char *buf, size_t buflen) | |
347 | static inline char *kernfs_path(struct kernfs_node *kn, char *buf, | 345 | { return -ENOSYS; } |
348 | size_t buflen) | ||
349 | { return NULL; } | ||
350 | 346 | ||
351 | static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { } | 347 | static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { } |
352 | static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { } | 348 | static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { } |
@@ -436,6 +432,22 @@ static inline void kernfs_init(void) { } | |||
436 | 432 | ||
437 | #endif /* CONFIG_KERNFS */ | 433 | #endif /* CONFIG_KERNFS */ |
438 | 434 | ||
435 | /** | ||
436 | * kernfs_path - build full path of a given node | ||
437 | * @kn: kernfs_node of interest | ||
438 | * @buf: buffer to copy @kn's name into | ||
439 | * @buflen: size of @buf | ||
440 | * | ||
441 | * Builds and returns the full path of @kn in @buf of @buflen bytes. The | ||
442 | * path is built from the end of @buf so the returned pointer usually | ||
443 | * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated | ||
444 | * and %NULL is returned. | ||
445 | */ | ||
446 | static inline int kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) | ||
447 | { | ||
448 | return kernfs_path_from_node(kn, NULL, buf, buflen); | ||
449 | } | ||
450 | |||
439 | static inline struct kernfs_node * | 451 | static inline struct kernfs_node * |
440 | kernfs_find_and_get(struct kernfs_node *kn, const char *name) | 452 | kernfs_find_and_get(struct kernfs_node *kn, const char *name) |
441 | { | 453 | { |
diff --git a/include/trace/events/cgroup.h b/include/trace/events/cgroup.h new file mode 100644 index 000000000000..ab68640a18d0 --- /dev/null +++ b/include/trace/events/cgroup.h | |||
@@ -0,0 +1,163 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM cgroup | ||
3 | |||
4 | #if !defined(_TRACE_CGROUP_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _TRACE_CGROUP_H | ||
6 | |||
7 | #include <linux/cgroup.h> | ||
8 | #include <linux/tracepoint.h> | ||
9 | |||
10 | DECLARE_EVENT_CLASS(cgroup_root, | ||
11 | |||
12 | TP_PROTO(struct cgroup_root *root), | ||
13 | |||
14 | TP_ARGS(root), | ||
15 | |||
16 | TP_STRUCT__entry( | ||
17 | __field( int, root ) | ||
18 | __field( u16, ss_mask ) | ||
19 | __string( name, root->name ) | ||
20 | ), | ||
21 | |||
22 | TP_fast_assign( | ||
23 | __entry->root = root->hierarchy_id; | ||
24 | __entry->ss_mask = root->subsys_mask; | ||
25 | __assign_str(name, root->name); | ||
26 | ), | ||
27 | |||
28 | TP_printk("root=%d ss_mask=%#x name=%s", | ||
29 | __entry->root, __entry->ss_mask, __get_str(name)) | ||
30 | ); | ||
31 | |||
32 | DEFINE_EVENT(cgroup_root, cgroup_setup_root, | ||
33 | |||
34 | TP_PROTO(struct cgroup_root *root), | ||
35 | |||
36 | TP_ARGS(root) | ||
37 | ); | ||
38 | |||
39 | DEFINE_EVENT(cgroup_root, cgroup_destroy_root, | ||
40 | |||
41 | TP_PROTO(struct cgroup_root *root), | ||
42 | |||
43 | TP_ARGS(root) | ||
44 | ); | ||
45 | |||
46 | DEFINE_EVENT(cgroup_root, cgroup_remount, | ||
47 | |||
48 | TP_PROTO(struct cgroup_root *root), | ||
49 | |||
50 | TP_ARGS(root) | ||
51 | ); | ||
52 | |||
53 | DECLARE_EVENT_CLASS(cgroup, | ||
54 | |||
55 | TP_PROTO(struct cgroup *cgrp), | ||
56 | |||
57 | TP_ARGS(cgrp), | ||
58 | |||
59 | TP_STRUCT__entry( | ||
60 | __field( int, root ) | ||
61 | __field( int, id ) | ||
62 | __field( int, level ) | ||
63 | __dynamic_array(char, path, | ||
64 | cgrp->kn ? cgroup_path(cgrp, NULL, 0) + 1 | ||
65 | : strlen("(null)")) | ||
66 | ), | ||
67 | |||
68 | TP_fast_assign( | ||
69 | __entry->root = cgrp->root->hierarchy_id; | ||
70 | __entry->id = cgrp->id; | ||
71 | __entry->level = cgrp->level; | ||
72 | if (cgrp->kn) | ||
73 | cgroup_path(cgrp, __get_dynamic_array(path), | ||
74 | __get_dynamic_array_len(path)); | ||
75 | else | ||
76 | __assign_str(path, "(null)"); | ||
77 | ), | ||
78 | |||
79 | TP_printk("root=%d id=%d level=%d path=%s", | ||
80 | __entry->root, __entry->id, __entry->level, __get_str(path)) | ||
81 | ); | ||
82 | |||
83 | DEFINE_EVENT(cgroup, cgroup_mkdir, | ||
84 | |||
85 | TP_PROTO(struct cgroup *cgroup), | ||
86 | |||
87 | TP_ARGS(cgroup) | ||
88 | ); | ||
89 | |||
90 | DEFINE_EVENT(cgroup, cgroup_rmdir, | ||
91 | |||
92 | TP_PROTO(struct cgroup *cgroup), | ||
93 | |||
94 | TP_ARGS(cgroup) | ||
95 | ); | ||
96 | |||
97 | DEFINE_EVENT(cgroup, cgroup_release, | ||
98 | |||
99 | TP_PROTO(struct cgroup *cgroup), | ||
100 | |||
101 | TP_ARGS(cgroup) | ||
102 | ); | ||
103 | |||
104 | DEFINE_EVENT(cgroup, cgroup_rename, | ||
105 | |||
106 | TP_PROTO(struct cgroup *cgroup), | ||
107 | |||
108 | TP_ARGS(cgroup) | ||
109 | ); | ||
110 | |||
111 | DECLARE_EVENT_CLASS(cgroup_migrate, | ||
112 | |||
113 | TP_PROTO(struct cgroup *dst_cgrp, struct task_struct *task, bool threadgroup), | ||
114 | |||
115 | TP_ARGS(dst_cgrp, task, threadgroup), | ||
116 | |||
117 | TP_STRUCT__entry( | ||
118 | __field( int, dst_root ) | ||
119 | __field( int, dst_id ) | ||
120 | __field( int, dst_level ) | ||
121 | __dynamic_array(char, dst_path, | ||
122 | dst_cgrp->kn ? cgroup_path(dst_cgrp, NULL, 0) + 1 | ||
123 | : strlen("(null)")) | ||
124 | __field( int, pid ) | ||
125 | __string( comm, task->comm ) | ||
126 | ), | ||
127 | |||
128 | TP_fast_assign( | ||
129 | __entry->dst_root = dst_cgrp->root->hierarchy_id; | ||
130 | __entry->dst_id = dst_cgrp->id; | ||
131 | __entry->dst_level = dst_cgrp->level; | ||
132 | if (dst_cgrp->kn) | ||
133 | cgroup_path(dst_cgrp, __get_dynamic_array(dst_path), | ||
134 | __get_dynamic_array_len(dst_path)); | ||
135 | else | ||
136 | __assign_str(dst_path, "(null)"); | ||
137 | __entry->pid = task->pid; | ||
138 | __assign_str(comm, task->comm); | ||
139 | ), | ||
140 | |||
141 | TP_printk("dst_root=%d dst_id=%d dst_level=%d dst_path=%s pid=%d comm=%s", | ||
142 | __entry->dst_root, __entry->dst_id, __entry->dst_level, | ||
143 | __get_str(dst_path), __entry->pid, __get_str(comm)) | ||
144 | ); | ||
145 | |||
146 | DEFINE_EVENT(cgroup_migrate, cgroup_attach_task, | ||
147 | |||
148 | TP_PROTO(struct cgroup *dst_cgrp, struct task_struct *task, bool threadgroup), | ||
149 | |||
150 | TP_ARGS(dst_cgrp, task, threadgroup) | ||
151 | ); | ||
152 | |||
153 | DEFINE_EVENT(cgroup_migrate, cgroup_transfer_tasks, | ||
154 | |||
155 | TP_PROTO(struct cgroup *dst_cgrp, struct task_struct *task, bool threadgroup), | ||
156 | |||
157 | TP_ARGS(dst_cgrp, task, threadgroup) | ||
158 | ); | ||
159 | |||
160 | #endif /* _TRACE_CGROUP_H */ | ||
161 | |||
162 | /* This part must be outside protection */ | ||
163 | #include <trace/define_trace.h> | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 44066158f0d1..85bc9beb046d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -64,6 +64,9 @@ | |||
64 | #include <linux/file.h> | 64 | #include <linux/file.h> |
65 | #include <net/sock.h> | 65 | #include <net/sock.h> |
66 | 66 | ||
67 | #define CREATE_TRACE_POINTS | ||
68 | #include <trace/events/cgroup.h> | ||
69 | |||
67 | /* | 70 | /* |
68 | * pidlists linger the following amount before being destroyed. The goal | 71 | * pidlists linger the following amount before being destroyed. The goal |
69 | * is avoiding frequent destruction in the middle of consecutive read calls | 72 | * is avoiding frequent destruction in the middle of consecutive read calls |
@@ -1176,6 +1179,8 @@ static void cgroup_destroy_root(struct cgroup_root *root) | |||
1176 | struct cgroup *cgrp = &root->cgrp; | 1179 | struct cgroup *cgrp = &root->cgrp; |
1177 | struct cgrp_cset_link *link, *tmp_link; | 1180 | struct cgrp_cset_link *link, *tmp_link; |
1178 | 1181 | ||
1182 | trace_cgroup_destroy_root(root); | ||
1183 | |||
1179 | cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp); | 1184 | cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp); |
1180 | 1185 | ||
1181 | BUG_ON(atomic_read(&root->nr_cgrps)); | 1186 | BUG_ON(atomic_read(&root->nr_cgrps)); |
@@ -1874,6 +1879,9 @@ static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data) | |||
1874 | strcpy(root->release_agent_path, opts.release_agent); | 1879 | strcpy(root->release_agent_path, opts.release_agent); |
1875 | spin_unlock(&release_agent_path_lock); | 1880 | spin_unlock(&release_agent_path_lock); |
1876 | } | 1881 | } |
1882 | |||
1883 | trace_cgroup_remount(root); | ||
1884 | |||
1877 | out_unlock: | 1885 | out_unlock: |
1878 | kfree(opts.release_agent); | 1886 | kfree(opts.release_agent); |
1879 | kfree(opts.name); | 1887 | kfree(opts.name); |
@@ -2031,6 +2039,8 @@ static int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) | |||
2031 | if (ret) | 2039 | if (ret) |
2032 | goto destroy_root; | 2040 | goto destroy_root; |
2033 | 2041 | ||
2042 | trace_cgroup_setup_root(root); | ||
2043 | |||
2034 | /* | 2044 | /* |
2035 | * There must be no failure case after here, since rebinding takes | 2045 | * There must be no failure case after here, since rebinding takes |
2036 | * care of subsystems' refcounts, which are explicitly dropped in | 2046 | * care of subsystems' refcounts, which are explicitly dropped in |
@@ -2315,22 +2325,18 @@ static struct file_system_type cgroup2_fs_type = { | |||
2315 | .fs_flags = FS_USERNS_MOUNT, | 2325 | .fs_flags = FS_USERNS_MOUNT, |
2316 | }; | 2326 | }; |
2317 | 2327 | ||
2318 | static char *cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, | 2328 | static int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, |
2319 | struct cgroup_namespace *ns) | 2329 | struct cgroup_namespace *ns) |
2320 | { | 2330 | { |
2321 | struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root); | 2331 | struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root); |
2322 | int ret; | ||
2323 | 2332 | ||
2324 | ret = kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen); | 2333 | return kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen); |
2325 | if (ret < 0 || ret >= buflen) | ||
2326 | return NULL; | ||
2327 | return buf; | ||
2328 | } | 2334 | } |
2329 | 2335 | ||
2330 | char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, | 2336 | int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, |
2331 | struct cgroup_namespace *ns) | 2337 | struct cgroup_namespace *ns) |
2332 | { | 2338 | { |
2333 | char *ret; | 2339 | int ret; |
2334 | 2340 | ||
2335 | mutex_lock(&cgroup_mutex); | 2341 | mutex_lock(&cgroup_mutex); |
2336 | spin_lock_irq(&css_set_lock); | 2342 | spin_lock_irq(&css_set_lock); |
@@ -2357,12 +2363,12 @@ EXPORT_SYMBOL_GPL(cgroup_path_ns); | |||
2357 | * | 2363 | * |
2358 | * Return value is the same as kernfs_path(). | 2364 | * Return value is the same as kernfs_path(). |
2359 | */ | 2365 | */ |
2360 | char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) | 2366 | int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) |
2361 | { | 2367 | { |
2362 | struct cgroup_root *root; | 2368 | struct cgroup_root *root; |
2363 | struct cgroup *cgrp; | 2369 | struct cgroup *cgrp; |
2364 | int hierarchy_id = 1; | 2370 | int hierarchy_id = 1; |
2365 | char *path = NULL; | 2371 | int ret; |
2366 | 2372 | ||
2367 | mutex_lock(&cgroup_mutex); | 2373 | mutex_lock(&cgroup_mutex); |
2368 | spin_lock_irq(&css_set_lock); | 2374 | spin_lock_irq(&css_set_lock); |
@@ -2371,16 +2377,15 @@ char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) | |||
2371 | 2377 | ||
2372 | if (root) { | 2378 | if (root) { |
2373 | cgrp = task_cgroup_from_root(task, root); | 2379 | cgrp = task_cgroup_from_root(task, root); |
2374 | path = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns); | 2380 | ret = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns); |
2375 | } else { | 2381 | } else { |
2376 | /* if no hierarchy exists, everyone is in "/" */ | 2382 | /* if no hierarchy exists, everyone is in "/" */ |
2377 | if (strlcpy(buf, "/", buflen) < buflen) | 2383 | ret = strlcpy(buf, "/", buflen); |
2378 | path = buf; | ||
2379 | } | 2384 | } |
2380 | 2385 | ||
2381 | spin_unlock_irq(&css_set_lock); | 2386 | spin_unlock_irq(&css_set_lock); |
2382 | mutex_unlock(&cgroup_mutex); | 2387 | mutex_unlock(&cgroup_mutex); |
2383 | return path; | 2388 | return ret; |
2384 | } | 2389 | } |
2385 | EXPORT_SYMBOL_GPL(task_cgroup_path); | 2390 | EXPORT_SYMBOL_GPL(task_cgroup_path); |
2386 | 2391 | ||
@@ -2830,6 +2835,10 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp, | |||
2830 | ret = cgroup_migrate(leader, threadgroup, dst_cgrp->root); | 2835 | ret = cgroup_migrate(leader, threadgroup, dst_cgrp->root); |
2831 | 2836 | ||
2832 | cgroup_migrate_finish(&preloaded_csets); | 2837 | cgroup_migrate_finish(&preloaded_csets); |
2838 | |||
2839 | if (!ret) | ||
2840 | trace_cgroup_attach_task(dst_cgrp, leader, threadgroup); | ||
2841 | |||
2833 | return ret; | 2842 | return ret; |
2834 | } | 2843 | } |
2835 | 2844 | ||
@@ -3611,6 +3620,8 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent, | |||
3611 | mutex_lock(&cgroup_mutex); | 3620 | mutex_lock(&cgroup_mutex); |
3612 | 3621 | ||
3613 | ret = kernfs_rename(kn, new_parent, new_name_str); | 3622 | ret = kernfs_rename(kn, new_parent, new_name_str); |
3623 | if (!ret) | ||
3624 | trace_cgroup_rename(cgrp); | ||
3614 | 3625 | ||
3615 | mutex_unlock(&cgroup_mutex); | 3626 | mutex_unlock(&cgroup_mutex); |
3616 | 3627 | ||
@@ -4381,6 +4392,8 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) | |||
4381 | 4392 | ||
4382 | if (task) { | 4393 | if (task) { |
4383 | ret = cgroup_migrate(task, false, to->root); | 4394 | ret = cgroup_migrate(task, false, to->root); |
4395 | if (!ret) | ||
4396 | trace_cgroup_transfer_tasks(to, task, false); | ||
4384 | put_task_struct(task); | 4397 | put_task_struct(task); |
4385 | } | 4398 | } |
4386 | } while (task && !ret); | 4399 | } while (task && !ret); |
@@ -5046,6 +5059,8 @@ static void css_release_work_fn(struct work_struct *work) | |||
5046 | ss->css_released(css); | 5059 | ss->css_released(css); |
5047 | } else { | 5060 | } else { |
5048 | /* cgroup release path */ | 5061 | /* cgroup release path */ |
5062 | trace_cgroup_release(cgrp); | ||
5063 | |||
5049 | cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); | 5064 | cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); |
5050 | cgrp->id = -1; | 5065 | cgrp->id = -1; |
5051 | 5066 | ||
@@ -5332,6 +5347,8 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, | |||
5332 | if (ret) | 5347 | if (ret) |
5333 | goto out_destroy; | 5348 | goto out_destroy; |
5334 | 5349 | ||
5350 | trace_cgroup_mkdir(cgrp); | ||
5351 | |||
5335 | /* let's create and online css's */ | 5352 | /* let's create and online css's */ |
5336 | kernfs_activate(kn); | 5353 | kernfs_activate(kn); |
5337 | 5354 | ||
@@ -5507,6 +5524,9 @@ static int cgroup_rmdir(struct kernfs_node *kn) | |||
5507 | 5524 | ||
5508 | ret = cgroup_destroy_locked(cgrp); | 5525 | ret = cgroup_destroy_locked(cgrp); |
5509 | 5526 | ||
5527 | if (!ret) | ||
5528 | trace_cgroup_rmdir(cgrp); | ||
5529 | |||
5510 | cgroup_kn_unlock(kn); | 5530 | cgroup_kn_unlock(kn); |
5511 | return ret; | 5531 | return ret; |
5512 | } | 5532 | } |
@@ -5743,7 +5763,7 @@ core_initcall(cgroup_wq_init); | |||
5743 | int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, | 5763 | int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, |
5744 | struct pid *pid, struct task_struct *tsk) | 5764 | struct pid *pid, struct task_struct *tsk) |
5745 | { | 5765 | { |
5746 | char *buf, *path; | 5766 | char *buf; |
5747 | int retval; | 5767 | int retval; |
5748 | struct cgroup_root *root; | 5768 | struct cgroup_root *root; |
5749 | 5769 | ||
@@ -5786,18 +5806,18 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, | |||
5786 | * " (deleted)" is appended to the cgroup path. | 5806 | * " (deleted)" is appended to the cgroup path. |
5787 | */ | 5807 | */ |
5788 | if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { | 5808 | if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { |
5789 | path = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, | 5809 | retval = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, |
5790 | current->nsproxy->cgroup_ns); | 5810 | current->nsproxy->cgroup_ns); |
5791 | if (!path) { | 5811 | if (retval >= PATH_MAX) |
5792 | retval = -ENAMETOOLONG; | 5812 | retval = -ENAMETOOLONG; |
5813 | if (retval < 0) | ||
5793 | goto out_unlock; | 5814 | goto out_unlock; |
5794 | } | 5815 | |
5816 | seq_puts(m, buf); | ||
5795 | } else { | 5817 | } else { |
5796 | path = "/"; | 5818 | seq_puts(m, "/"); |
5797 | } | 5819 | } |
5798 | 5820 | ||
5799 | seq_puts(m, path); | ||
5800 | |||
5801 | if (cgroup_on_dfl(cgrp) && cgroup_is_dead(cgrp)) | 5821 | if (cgroup_on_dfl(cgrp) && cgroup_is_dead(cgrp)) |
5802 | seq_puts(m, " (deleted)\n"); | 5822 | seq_puts(m, " (deleted)\n"); |
5803 | else | 5823 | else |
@@ -6062,8 +6082,9 @@ static void cgroup_release_agent(struct work_struct *work) | |||
6062 | { | 6082 | { |
6063 | struct cgroup *cgrp = | 6083 | struct cgroup *cgrp = |
6064 | container_of(work, struct cgroup, release_agent_work); | 6084 | container_of(work, struct cgroup, release_agent_work); |
6065 | char *pathbuf = NULL, *agentbuf = NULL, *path; | 6085 | char *pathbuf = NULL, *agentbuf = NULL; |
6066 | char *argv[3], *envp[3]; | 6086 | char *argv[3], *envp[3]; |
6087 | int ret; | ||
6067 | 6088 | ||
6068 | mutex_lock(&cgroup_mutex); | 6089 | mutex_lock(&cgroup_mutex); |
6069 | 6090 | ||
@@ -6073,13 +6094,13 @@ static void cgroup_release_agent(struct work_struct *work) | |||
6073 | goto out; | 6094 | goto out; |
6074 | 6095 | ||
6075 | spin_lock_irq(&css_set_lock); | 6096 | spin_lock_irq(&css_set_lock); |
6076 | path = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); | 6097 | ret = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); |
6077 | spin_unlock_irq(&css_set_lock); | 6098 | spin_unlock_irq(&css_set_lock); |
6078 | if (!path) | 6099 | if (ret < 0 || ret >= PATH_MAX) |
6079 | goto out; | 6100 | goto out; |
6080 | 6101 | ||
6081 | argv[0] = agentbuf; | 6102 | argv[0] = agentbuf; |
6082 | argv[1] = path; | 6103 | argv[1] = pathbuf; |
6083 | argv[2] = NULL; | 6104 | argv[2] = NULL; |
6084 | 6105 | ||
6085 | /* minimal command environment */ | 6106 | /* minimal command environment */ |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 2b4c20ab5bbe..29f815d2ef7e 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -2715,7 +2715,7 @@ void __cpuset_memory_pressure_bump(void) | |||
2715 | int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, | 2715 | int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, |
2716 | struct pid *pid, struct task_struct *tsk) | 2716 | struct pid *pid, struct task_struct *tsk) |
2717 | { | 2717 | { |
2718 | char *buf, *p; | 2718 | char *buf; |
2719 | struct cgroup_subsys_state *css; | 2719 | struct cgroup_subsys_state *css; |
2720 | int retval; | 2720 | int retval; |
2721 | 2721 | ||
@@ -2724,14 +2724,15 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, | |||
2724 | if (!buf) | 2724 | if (!buf) |
2725 | goto out; | 2725 | goto out; |
2726 | 2726 | ||
2727 | retval = -ENAMETOOLONG; | ||
2728 | css = task_get_css(tsk, cpuset_cgrp_id); | 2727 | css = task_get_css(tsk, cpuset_cgrp_id); |
2729 | p = cgroup_path_ns(css->cgroup, buf, PATH_MAX, | 2728 | retval = cgroup_path_ns(css->cgroup, buf, PATH_MAX, |
2730 | current->nsproxy->cgroup_ns); | 2729 | current->nsproxy->cgroup_ns); |
2731 | css_put(css); | 2730 | css_put(css); |
2732 | if (!p) | 2731 | if (retval >= PATH_MAX) |
2732 | retval = -ENAMETOOLONG; | ||
2733 | if (retval < 0) | ||
2733 | goto out_free; | 2734 | goto out_free; |
2734 | seq_puts(m, p); | 2735 | seq_puts(m, buf); |
2735 | seq_putc(m, '\n'); | 2736 | seq_putc(m, '\n'); |
2736 | retval = 0; | 2737 | retval = 0; |
2737 | out_free: | 2738 | out_free: |
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 13935886a471..fa178b62ea79 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c | |||
@@ -415,7 +415,8 @@ static char *task_group_path(struct task_group *tg) | |||
415 | if (autogroup_path(tg, group_path, PATH_MAX)) | 415 | if (autogroup_path(tg, group_path, PATH_MAX)) |
416 | return group_path; | 416 | return group_path; |
417 | 417 | ||
418 | return cgroup_path(tg->css.cgroup, group_path, PATH_MAX); | 418 | cgroup_path(tg->css.cgroup, group_path, PATH_MAX); |
419 | return group_path; | ||
419 | } | 420 | } |
420 | #endif | 421 | #endif |
421 | 422 | ||