aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Zanussi <tzanussi@gmail.com>2009-04-17 01:27:08 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-17 12:28:27 -0400
commitac1adc55fc71c7515caa2eb0e63e49b3d1c6a47c (patch)
tree7a97cf9512572c53d0802725f8e0ad6a2d4b2204
parent46de405f25f1d9fa73b657ffbb752aa0cc87a91d (diff)
tracing/filters: add filter_mutex to protect filter predicates
This patch adds a filter_mutex to prevent the filter predicates from being accessed concurrently by various external functions. It's based on a previous patch by Li Zefan: "[PATCH 7/7] tracing/filters: make filter preds RCU safe" v2 changes: - fixed wrong value returned in a add_subsystem_pred() failure case noticed by Li Zefan. [ Impact: fix trace filter corruption/crashes on parallel access ] Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Reviewed-by: Li Zefan <lizf@cn.fujitsu.com> Tested-by: Li Zefan <lizf@cn.fujitsu.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: paulmck@linux.vnet.ibm.com LKML-Reference: <1239946028.6639.13.camel@tropicana> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--kernel/trace/trace.h4
-rw-r--r--kernel/trace/trace_events.c4
-rw-r--r--kernel/trace/trace_events_filter.c90
3 files changed, 75 insertions, 23 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 8817c18ef97a..247948e81b08 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -757,13 +757,15 @@ struct filter_pred {
757}; 757};
758 758
759extern void filter_free_pred(struct filter_pred *pred); 759extern void filter_free_pred(struct filter_pred *pred);
760extern void filter_print_preds(struct filter_pred **preds, int n_preds, 760extern void filter_print_preds(struct ftrace_event_call *call,
761 struct trace_seq *s); 761 struct trace_seq *s);
762extern int filter_parse(char **pbuf, struct filter_pred *pred); 762extern int filter_parse(char **pbuf, struct filter_pred *pred);
763extern int filter_add_pred(struct ftrace_event_call *call, 763extern int filter_add_pred(struct ftrace_event_call *call,
764 struct filter_pred *pred); 764 struct filter_pred *pred);
765extern void filter_disable_preds(struct ftrace_event_call *call); 765extern void filter_disable_preds(struct ftrace_event_call *call);
766extern void filter_free_subsystem_preds(struct event_subsystem *system); 766extern void filter_free_subsystem_preds(struct event_subsystem *system);
767extern void filter_print_subsystem_preds(struct event_subsystem *system,
768 struct trace_seq *s);
767extern int filter_add_subsystem_pred(struct event_subsystem *system, 769extern int filter_add_subsystem_pred(struct event_subsystem *system,
768 struct filter_pred *pred); 770 struct filter_pred *pred);
769 771
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 1137f951be42..64f9d6d2735b 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -488,7 +488,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
488 488
489 trace_seq_init(s); 489 trace_seq_init(s);
490 490
491 filter_print_preds(call->preds, call->n_preds, s); 491 filter_print_preds(call, s);
492 r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); 492 r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
493 493
494 kfree(s); 494 kfree(s);
@@ -558,7 +558,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
558 558
559 trace_seq_init(s); 559 trace_seq_init(s);
560 560
561 filter_print_preds(system->preds, system->n_preds, s); 561 filter_print_subsystem_preds(system, s);
562 r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); 562 r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
563 563
564 kfree(s); 564 kfree(s);
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index f8e5eab0424c..e0fcfd2a16d6 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -22,10 +22,13 @@
22#include <linux/uaccess.h> 22#include <linux/uaccess.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/ctype.h> 24#include <linux/ctype.h>
25#include <linux/mutex.h>
25 26
26#include "trace.h" 27#include "trace.h"
27#include "trace_output.h" 28#include "trace_output.h"
28 29
30static DEFINE_MUTEX(filter_mutex);
31
29static int filter_pred_64(struct filter_pred *pred, void *event) 32static int filter_pred_64(struct filter_pred *pred, void *event)
30{ 33{
31 u64 *addr = (u64 *)(event + pred->offset); 34 u64 *addr = (u64 *)(event + pred->offset);
@@ -112,8 +115,8 @@ int filter_match_preds(struct ftrace_event_call *call, void *rec)
112} 115}
113EXPORT_SYMBOL_GPL(filter_match_preds); 116EXPORT_SYMBOL_GPL(filter_match_preds);
114 117
115void filter_print_preds(struct filter_pred **preds, int n_preds, 118static void __filter_print_preds(struct filter_pred **preds, int n_preds,
116 struct trace_seq *s) 119 struct trace_seq *s)
117{ 120{
118 char *field_name; 121 char *field_name;
119 struct filter_pred *pred; 122 struct filter_pred *pred;
@@ -138,6 +141,21 @@ void filter_print_preds(struct filter_pred **preds, int n_preds,
138 } 141 }
139} 142}
140 143
144void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s)
145{
146 mutex_lock(&filter_mutex);
147 __filter_print_preds(call->preds, call->n_preds, s);
148 mutex_unlock(&filter_mutex);
149}
150
151void filter_print_subsystem_preds(struct event_subsystem *system,
152 struct trace_seq *s)
153{
154 mutex_lock(&filter_mutex);
155 __filter_print_preds(system->preds, system->n_preds, s);
156 mutex_unlock(&filter_mutex);
157}
158
141static struct ftrace_event_field * 159static struct ftrace_event_field *
142find_event_field(struct ftrace_event_call *call, char *name) 160find_event_field(struct ftrace_event_call *call, char *name)
143{ 161{
@@ -180,7 +198,7 @@ static int filter_set_pred(struct filter_pred *dest,
180 return 0; 198 return 0;
181} 199}
182 200
183void filter_disable_preds(struct ftrace_event_call *call) 201static void __filter_disable_preds(struct ftrace_event_call *call)
184{ 202{
185 int i; 203 int i;
186 204
@@ -190,6 +208,13 @@ void filter_disable_preds(struct ftrace_event_call *call)
190 call->preds[i]->fn = filter_pred_none; 208 call->preds[i]->fn = filter_pred_none;
191} 209}
192 210
211void filter_disable_preds(struct ftrace_event_call *call)
212{
213 mutex_lock(&filter_mutex);
214 __filter_disable_preds(call);
215 mutex_unlock(&filter_mutex);
216}
217
193int init_preds(struct ftrace_event_call *call) 218int init_preds(struct ftrace_event_call *call)
194{ 219{
195 struct filter_pred *pred; 220 struct filter_pred *pred;
@@ -223,7 +248,7 @@ oom:
223} 248}
224EXPORT_SYMBOL_GPL(init_preds); 249EXPORT_SYMBOL_GPL(init_preds);
225 250
226void filter_free_subsystem_preds(struct event_subsystem *system) 251static void __filter_free_subsystem_preds(struct event_subsystem *system)
227{ 252{
228 struct ftrace_event_call *call; 253 struct ftrace_event_call *call;
229 int i; 254 int i;
@@ -241,18 +266,25 @@ void filter_free_subsystem_preds(struct event_subsystem *system)
241 continue; 266 continue;
242 267
243 if (!strcmp(call->system, system->name)) 268 if (!strcmp(call->system, system->name))
244 filter_disable_preds(call); 269 __filter_disable_preds(call);
245 } 270 }
246} 271}
247 272
248static int __filter_add_pred(struct ftrace_event_call *call, 273void filter_free_subsystem_preds(struct event_subsystem *system)
249 struct filter_pred *pred, 274{
250 filter_pred_fn_t fn) 275 mutex_lock(&filter_mutex);
276 __filter_free_subsystem_preds(system);
277 mutex_unlock(&filter_mutex);
278}
279
280static int filter_add_pred_fn(struct ftrace_event_call *call,
281 struct filter_pred *pred,
282 filter_pred_fn_t fn)
251{ 283{
252 int idx, err; 284 int idx, err;
253 285
254 if (call->n_preds && !pred->compound) 286 if (call->n_preds && !pred->compound)
255 filter_disable_preds(call); 287 __filter_disable_preds(call);
256 288
257 if (call->n_preds == MAX_FILTER_PRED) 289 if (call->n_preds == MAX_FILTER_PRED)
258 return -ENOSPC; 290 return -ENOSPC;
@@ -276,7 +308,8 @@ static int is_string_field(const char *type)
276 return 0; 308 return 0;
277} 309}
278 310
279int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred) 311static int __filter_add_pred(struct ftrace_event_call *call,
312 struct filter_pred *pred)
280{ 313{
281 struct ftrace_event_field *field; 314 struct ftrace_event_field *field;
282 filter_pred_fn_t fn; 315 filter_pred_fn_t fn;
@@ -293,7 +326,7 @@ int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
293 return -EINVAL; 326 return -EINVAL;
294 fn = filter_pred_string; 327 fn = filter_pred_string;
295 pred->str_len = field->size; 328 pred->str_len = field->size;
296 return __filter_add_pred(call, pred, fn); 329 return filter_add_pred_fn(call, pred, fn);
297 } else { 330 } else {
298 if (pred->str_len) 331 if (pred->str_len)
299 return -EINVAL; 332 return -EINVAL;
@@ -316,7 +349,18 @@ int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
316 return -EINVAL; 349 return -EINVAL;
317 } 350 }
318 351
319 return __filter_add_pred(call, pred, fn); 352 return filter_add_pred_fn(call, pred, fn);
353}
354
355int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
356{
357 int err;
358
359 mutex_lock(&filter_mutex);
360 err = __filter_add_pred(call, pred);
361 mutex_unlock(&filter_mutex);
362
363 return err;
320} 364}
321 365
322int filter_add_subsystem_pred(struct event_subsystem *system, 366int filter_add_subsystem_pred(struct event_subsystem *system,
@@ -324,20 +368,27 @@ int filter_add_subsystem_pred(struct event_subsystem *system,
324{ 368{
325 struct ftrace_event_call *call; 369 struct ftrace_event_call *call;
326 370
371 mutex_lock(&filter_mutex);
372
327 if (system->n_preds && !pred->compound) 373 if (system->n_preds && !pred->compound)
328 filter_free_subsystem_preds(system); 374 __filter_free_subsystem_preds(system);
329 375
330 if (!system->n_preds) { 376 if (!system->n_preds) {
331 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), 377 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
332 GFP_KERNEL); 378 GFP_KERNEL);
333 if (!system->preds) 379 if (!system->preds) {
380 mutex_unlock(&filter_mutex);
334 return -ENOMEM; 381 return -ENOMEM;
382 }
335 } 383 }
336 384
337 if (system->n_preds == MAX_FILTER_PRED) 385 if (system->n_preds == MAX_FILTER_PRED) {
386 mutex_unlock(&filter_mutex);
338 return -ENOSPC; 387 return -ENOSPC;
388 }
339 389
340 system->preds[system->n_preds] = pred; 390 system->preds[system->n_preds] = pred;
391 system->n_preds++;
341 392
342 list_for_each_entry(call, &ftrace_events, list) { 393 list_for_each_entry(call, &ftrace_events, list) {
343 int err; 394 int err;
@@ -348,17 +399,16 @@ int filter_add_subsystem_pred(struct event_subsystem *system,
348 if (strcmp(call->system, system->name)) 399 if (strcmp(call->system, system->name))
349 continue; 400 continue;
350 401
351 if (!find_event_field(call, pred->field_name)) 402 err = __filter_add_pred(call, pred);
352 continue;
353
354 err = filter_add_pred(call, pred);
355 if (err == -ENOMEM) { 403 if (err == -ENOMEM) {
356 system->preds[system->n_preds] = NULL; 404 system->preds[system->n_preds] = NULL;
405 system->n_preds--;
406 mutex_unlock(&filter_mutex);
357 return err; 407 return err;
358 } 408 }
359 } 409 }
360 410
361 system->n_preds++; 411 mutex_unlock(&filter_mutex);
362 412
363 return 0; 413 return 0;
364} 414}