diff options
author | Tejun Heo <tj@kernel.org> | 2016-08-10 11:23:44 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2016-08-10 11:23:44 -0400 |
commit | ed1777de25e45bfb58fad63341904f8a77911785 (patch) | |
tree | e7fb66fbbcee5c7fa0bde752bd6ecf44e65b4d1c | |
parent | 4c737b41de7f4eef2a593803bad1b918dd718b10 (diff) |
cgroup: add tracepoints for basic operations
Debugging what goes wrong with cgroup setup can get hairy. Add
tracepoints for cgroup hierarchy mount, cgroup creation/destruction
and task migration operations for better visibility.
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | include/trace/events/cgroup.h | 163 | ||||
-rw-r--r-- | kernel/cgroup.c | 25 |
2 files changed, 188 insertions, 0 deletions
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 3861161e460f..5e2e81ad9175 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 |
@@ -2825,6 +2835,10 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp, | |||
2825 | ret = cgroup_migrate(leader, threadgroup, dst_cgrp->root); | 2835 | ret = cgroup_migrate(leader, threadgroup, dst_cgrp->root); |
2826 | 2836 | ||
2827 | 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 | |||
2828 | return ret; | 2842 | return ret; |
2829 | } | 2843 | } |
2830 | 2844 | ||
@@ -3587,6 +3601,8 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent, | |||
3587 | mutex_lock(&cgroup_mutex); | 3601 | mutex_lock(&cgroup_mutex); |
3588 | 3602 | ||
3589 | ret = kernfs_rename(kn, new_parent, new_name_str); | 3603 | ret = kernfs_rename(kn, new_parent, new_name_str); |
3604 | if (!ret) | ||
3605 | trace_cgroup_rename(cgrp); | ||
3590 | 3606 | ||
3591 | mutex_unlock(&cgroup_mutex); | 3607 | mutex_unlock(&cgroup_mutex); |
3592 | 3608 | ||
@@ -4355,6 +4371,8 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) | |||
4355 | 4371 | ||
4356 | if (task) { | 4372 | if (task) { |
4357 | ret = cgroup_migrate(task, false, to->root); | 4373 | ret = cgroup_migrate(task, false, to->root); |
4374 | if (!ret) | ||
4375 | trace_cgroup_transfer_tasks(to, task, false); | ||
4358 | put_task_struct(task); | 4376 | put_task_struct(task); |
4359 | } | 4377 | } |
4360 | } while (task && !ret); | 4378 | } while (task && !ret); |
@@ -5020,6 +5038,8 @@ static void css_release_work_fn(struct work_struct *work) | |||
5020 | ss->css_released(css); | 5038 | ss->css_released(css); |
5021 | } else { | 5039 | } else { |
5022 | /* cgroup release path */ | 5040 | /* cgroup release path */ |
5041 | trace_cgroup_release(cgrp); | ||
5042 | |||
5023 | cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); | 5043 | cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); |
5024 | cgrp->id = -1; | 5044 | cgrp->id = -1; |
5025 | 5045 | ||
@@ -5306,6 +5326,8 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, | |||
5306 | if (ret) | 5326 | if (ret) |
5307 | goto out_destroy; | 5327 | goto out_destroy; |
5308 | 5328 | ||
5329 | trace_cgroup_mkdir(cgrp); | ||
5330 | |||
5309 | /* let's create and online css's */ | 5331 | /* let's create and online css's */ |
5310 | kernfs_activate(kn); | 5332 | kernfs_activate(kn); |
5311 | 5333 | ||
@@ -5481,6 +5503,9 @@ static int cgroup_rmdir(struct kernfs_node *kn) | |||
5481 | 5503 | ||
5482 | ret = cgroup_destroy_locked(cgrp); | 5504 | ret = cgroup_destroy_locked(cgrp); |
5483 | 5505 | ||
5506 | if (!ret) | ||
5507 | trace_cgroup_rmdir(cgrp); | ||
5508 | |||
5484 | cgroup_kn_unlock(kn); | 5509 | cgroup_kn_unlock(kn); |
5485 | return ret; | 5510 | return ret; |
5486 | } | 5511 | } |