aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2011-08-11 10:25:49 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-08-19 14:35:54 -0400
commitf03f5979945c573801c25ba3089ef17c4d7edc61 (patch)
treed26c45bd4c7fd26e2a635bf08612a1e09d8038c5 /kernel/trace
parent3f78f935e7fec3067b7990f9e4d324e1de70f79c (diff)
tracing/filter: Unify predicate tree walking, change check_pred_tree function to use it
Adding walk_pred_tree function to be used for walking throught the filter predicates. For each predicate the callback function is called, allowing users to add their own functionality or customize their way through the filter predicates. Changing check_pred_tree function to use walk_pred_tree. Signed-off-by: Jiri Olsa <jolsa@redhat.com> Link: http://lkml.kernel.org/r/1313072754-4620-6-git-send-email-jolsa@redhat.com Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_events_filter.c137
1 files changed, 86 insertions, 51 deletions
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 0948905dd39c..5b889d43d856 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -381,6 +381,63 @@ get_pred_parent(struct filter_pred *pred, struct filter_pred *preds,
381 return pred; 381 return pred;
382} 382}
383 383
384enum walk_return {
385 WALK_PRED_ABORT,
386 WALK_PRED_PARENT,
387 WALK_PRED_DEFAULT,
388};
389
390typedef int (*filter_pred_walkcb_t) (enum move_type move,
391 struct filter_pred *pred,
392 int *err, void *data);
393
394static int walk_pred_tree(struct filter_pred *preds,
395 struct filter_pred *root,
396 filter_pred_walkcb_t cb, void *data)
397{
398 struct filter_pred *pred = root;
399 enum move_type move = MOVE_DOWN;
400 int done = 0;
401
402 if (!preds)
403 return -EINVAL;
404
405 do {
406 int err = 0, ret;
407
408 ret = cb(move, pred, &err, data);
409 if (ret == WALK_PRED_ABORT)
410 return err;
411 if (ret == WALK_PRED_PARENT)
412 goto get_parent;
413
414 switch (move) {
415 case MOVE_DOWN:
416 if (pred->left != FILTER_PRED_INVALID) {
417 pred = &preds[pred->left];
418 continue;
419 }
420 goto get_parent;
421 case MOVE_UP_FROM_LEFT:
422 pred = &preds[pred->right];
423 move = MOVE_DOWN;
424 continue;
425 case MOVE_UP_FROM_RIGHT:
426 get_parent:
427 if (pred == root)
428 break;
429 pred = get_pred_parent(pred, preds,
430 pred->parent,
431 &move);
432 continue;
433 }
434 done = 1;
435 } while (!done);
436
437 /* We are fine. */
438 return 0;
439}
440
384/* 441/*
385 * A series of AND or ORs where found together. Instead of 442 * A series of AND or ORs where found together. Instead of
386 * climbing up and down the tree branches, an array of the 443 * climbing up and down the tree branches, an array of the
@@ -1321,6 +1378,23 @@ static int count_preds(struct filter_parse_state *ps)
1321 return n_preds; 1378 return n_preds;
1322} 1379}
1323 1380
1381struct check_pred_data {
1382 int count;
1383 int max;
1384};
1385
1386static int check_pred_tree_cb(enum move_type move, struct filter_pred *pred,
1387 int *err, void *data)
1388{
1389 struct check_pred_data *d = data;
1390
1391 if (WARN_ON(d->count++ > d->max)) {
1392 *err = -EINVAL;
1393 return WALK_PRED_ABORT;
1394 }
1395 return WALK_PRED_DEFAULT;
1396}
1397
1324/* 1398/*
1325 * The tree is walked at filtering of an event. If the tree is not correctly 1399 * The tree is walked at filtering of an event. If the tree is not correctly
1326 * built, it may cause an infinite loop. Check here that the tree does 1400 * built, it may cause an infinite loop. Check here that the tree does
@@ -1329,58 +1403,19 @@ static int count_preds(struct filter_parse_state *ps)
1329static int check_pred_tree(struct event_filter *filter, 1403static int check_pred_tree(struct event_filter *filter,
1330 struct filter_pred *root) 1404 struct filter_pred *root)
1331{ 1405{
1332 struct filter_pred *preds; 1406 struct check_pred_data data = {
1333 struct filter_pred *pred; 1407 /*
1334 enum move_type move = MOVE_DOWN; 1408 * The max that we can hit a node is three times.
1335 int count = 0; 1409 * Once going down, once coming up from left, and
1336 int done = 0; 1410 * once coming up from right. This is more than enough
1337 int max; 1411 * since leafs are only hit a single time.
1338 1412 */
1339 /* 1413 .max = 3 * filter->n_preds,
1340 * The max that we can hit a node is three times. 1414 .count = 0,
1341 * Once going down, once coming up from left, and 1415 };
1342 * once coming up from right. This is more than enough
1343 * since leafs are only hit a single time.
1344 */
1345 max = 3 * filter->n_preds;
1346
1347 preds = filter->preds;
1348 if (!preds)
1349 return -EINVAL;
1350 pred = root;
1351
1352 do {
1353 if (WARN_ON(count++ > max))
1354 return -EINVAL;
1355
1356 switch (move) {
1357 case MOVE_DOWN:
1358 if (pred->left != FILTER_PRED_INVALID) {
1359 pred = &preds[pred->left];
1360 continue;
1361 }
1362 /* A leaf at the root is just a leaf in the tree */
1363 if (pred == root)
1364 break;
1365 pred = get_pred_parent(pred, preds,
1366 pred->parent, &move);
1367 continue;
1368 case MOVE_UP_FROM_LEFT:
1369 pred = &preds[pred->right];
1370 move = MOVE_DOWN;
1371 continue;
1372 case MOVE_UP_FROM_RIGHT:
1373 if (pred == root)
1374 break;
1375 pred = get_pred_parent(pred, preds,
1376 pred->parent, &move);
1377 continue;
1378 }
1379 done = 1;
1380 } while (!done);
1381 1416
1382 /* We are fine. */ 1417 return walk_pred_tree(filter->preds, root,
1383 return 0; 1418 check_pred_tree_cb, &data);
1384} 1419}
1385 1420
1386static int count_leafs(struct filter_pred *preds, struct filter_pred *root) 1421static int count_leafs(struct filter_pred *preds, struct filter_pred *root)