diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_stat.c | 54 |
1 files changed, 21 insertions, 33 deletions
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c index 8030ec98dbad..17f20ebdad2a 100644 --- a/kernel/trace/trace_stat.c +++ b/kernel/trace/trace_stat.c | |||
@@ -93,10 +93,15 @@ static void destroy_session(struct stat_session *session) | |||
93 | 93 | ||
94 | typedef int (*cmp_stat_t)(void *, void *); | 94 | typedef int (*cmp_stat_t)(void *, void *); |
95 | 95 | ||
96 | static void | 96 | static int insert_stat(struct rb_root *root, void *stat, cmp_stat_t cmp) |
97 | insert_stat(struct rb_root *root, struct stat_node *data, cmp_stat_t cmp) | ||
98 | { | 97 | { |
99 | struct rb_node **new = &(root->rb_node), *parent = NULL; | 98 | struct rb_node **new = &(root->rb_node), *parent = NULL; |
99 | struct stat_node *data; | ||
100 | |||
101 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
102 | if (!data) | ||
103 | return -ENOMEM; | ||
104 | data->stat = stat; | ||
100 | 105 | ||
101 | /* | 106 | /* |
102 | * Figure out where to put new node | 107 | * Figure out where to put new node |
@@ -118,12 +123,13 @@ insert_stat(struct rb_root *root, struct stat_node *data, cmp_stat_t cmp) | |||
118 | 123 | ||
119 | rb_link_node(&data->node, parent, new); | 124 | rb_link_node(&data->node, parent, new); |
120 | rb_insert_color(&data->node, root); | 125 | rb_insert_color(&data->node, root); |
126 | return 0; | ||
121 | } | 127 | } |
122 | 128 | ||
123 | /* | 129 | /* |
124 | * For tracers that don't provide a stat_cmp callback. | 130 | * For tracers that don't provide a stat_cmp callback. |
125 | * This one will force an immediate insertion on tail of | 131 | * This one will force an insertion as right-most node |
126 | * the list. | 132 | * in the rbtree. |
127 | */ | 133 | */ |
128 | static int dummy_cmp(void *p1, void *p2) | 134 | static int dummy_cmp(void *p1, void *p2) |
129 | { | 135 | { |
@@ -131,15 +137,14 @@ static int dummy_cmp(void *p1, void *p2) | |||
131 | } | 137 | } |
132 | 138 | ||
133 | /* | 139 | /* |
134 | * Initialize the stat list at each trace_stat file opening. | 140 | * Initialize the stat rbtree at each trace_stat file opening. |
135 | * All of these copies and sorting are required on all opening | 141 | * All of these copies and sorting are required on all opening |
136 | * since the stats could have changed between two file sessions. | 142 | * since the stats could have changed between two file sessions. |
137 | */ | 143 | */ |
138 | static int stat_seq_init(struct stat_session *session) | 144 | static int stat_seq_init(struct stat_session *session) |
139 | { | 145 | { |
140 | struct tracer_stat *ts = session->ts; | 146 | struct tracer_stat *ts = session->ts; |
141 | struct stat_node *new_entry; | 147 | struct rb_root *root = &session->stat_root; |
142 | struct rb_root *root; | ||
143 | void *stat; | 148 | void *stat; |
144 | int ret = 0; | 149 | int ret = 0; |
145 | int i; | 150 | int i; |
@@ -154,23 +159,12 @@ static int stat_seq_init(struct stat_session *session) | |||
154 | if (!stat) | 159 | if (!stat) |
155 | goto exit; | 160 | goto exit; |
156 | 161 | ||
157 | /* | 162 | ret = insert_stat(root, stat, ts->stat_cmp); |
158 | * The first entry. Actually this is the second, but the first | 163 | if (ret) |
159 | * one (the stat_list head) is pointless. | ||
160 | */ | ||
161 | new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); | ||
162 | if (!new_entry) { | ||
163 | ret = -ENOMEM; | ||
164 | goto exit; | 164 | goto exit; |
165 | } | ||
166 | root = &session->stat_root; | ||
167 | insert_stat(root, new_entry, dummy_cmp); | ||
168 | |||
169 | new_entry->stat = stat; | ||
170 | 165 | ||
171 | /* | 166 | /* |
172 | * Iterate over the tracer stat entries and store them in a sorted | 167 | * Iterate over the tracer stat entries and store them in an rbtree. |
173 | * list. | ||
174 | */ | 168 | */ |
175 | for (i = 1; ; i++) { | 169 | for (i = 1; ; i++) { |
176 | stat = ts->stat_next(stat, i); | 170 | stat = ts->stat_next(stat, i); |
@@ -179,22 +173,16 @@ static int stat_seq_init(struct stat_session *session) | |||
179 | if (!stat) | 173 | if (!stat) |
180 | break; | 174 | break; |
181 | 175 | ||
182 | new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); | 176 | ret = insert_stat(root, stat, ts->stat_cmp); |
183 | if (!new_entry) { | 177 | if (ret) |
184 | ret = -ENOMEM; | 178 | goto exit_free_rbtree; |
185 | goto exit_free_list; | ||
186 | } | ||
187 | |||
188 | new_entry->stat = stat; | ||
189 | |||
190 | insert_stat(root, new_entry, ts->stat_cmp); | ||
191 | } | 179 | } |
192 | 180 | ||
193 | exit: | 181 | exit: |
194 | mutex_unlock(&session->stat_mutex); | 182 | mutex_unlock(&session->stat_mutex); |
195 | return ret; | 183 | return ret; |
196 | 184 | ||
197 | exit_free_list: | 185 | exit_free_rbtree: |
198 | reset_stat_session(session); | 186 | reset_stat_session(session); |
199 | mutex_unlock(&session->stat_mutex); | 187 | mutex_unlock(&session->stat_mutex); |
200 | return ret; | 188 | return ret; |
@@ -207,7 +195,7 @@ static void *stat_seq_start(struct seq_file *s, loff_t *pos) | |||
207 | struct rb_node *node; | 195 | struct rb_node *node; |
208 | int i; | 196 | int i; |
209 | 197 | ||
210 | /* Prevent from tracer switch or stat_list modification */ | 198 | /* Prevent from tracer switch or rbtree modification */ |
211 | mutex_lock(&session->stat_mutex); | 199 | mutex_lock(&session->stat_mutex); |
212 | 200 | ||
213 | /* If we are in the beginning of the file, print the headers */ | 201 | /* If we are in the beginning of the file, print the headers */ |
@@ -280,7 +268,7 @@ static int tracing_stat_open(struct inode *inode, struct file *file) | |||
280 | } | 268 | } |
281 | 269 | ||
282 | /* | 270 | /* |
283 | * Avoid consuming memory with our now useless list. | 271 | * Avoid consuming memory with our now useless rbtree. |
284 | */ | 272 | */ |
285 | static int tracing_stat_release(struct inode *i, struct file *f) | 273 | static int tracing_stat_release(struct inode *i, struct file *f) |
286 | { | 274 | { |