66 */
77#include <getopt.h>
88#include <stdlib.h>
9+ #include <stdio.h>
910#include <string.h>
1011#include <errno.h>
1112#include <unistd.h>
13+ #include <dirent.h>
1214
1315#include <trace.h>
1416#include <utils.h>
1517#include <rv.h>
1618
1719static int config_has_id ;
20+ static int config_is_container ;
1821static int config_my_pid ;
1922static int config_trace ;
2023
@@ -44,6 +47,51 @@ static int __ikm_read_enable(char *monitor_name)
4447 return enabled ;
4548}
4649
50+ /*
51+ * __ikm_find_monitor - find the full name of a possibly nested module
52+ *
53+ * __does not log errors.
54+ *
55+ * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist.
56+ * The string out_name is populated with the full name, which can be
57+ * equal to monitor_name or container/monitor_name if nested
58+ */
59+ static int __ikm_find_monitor_name (char * monitor_name , char * out_name )
60+ {
61+ char * available_monitors , container [MAX_DA_NAME_LEN + 1 ], * cursor , * end ;
62+ int retval = 1 ;
63+
64+ available_monitors = tracefs_instance_file_read (NULL , "rv/available_monitors" , NULL );
65+ if (!available_monitors )
66+ return -1 ;
67+
68+ cursor = strstr (available_monitors , monitor_name );
69+ if (!cursor ) {
70+ retval = 0 ;
71+ goto out_free ;
72+ }
73+
74+ for (; cursor > available_monitors ; cursor -- )
75+ if (* (cursor - 1 ) == '\n' )
76+ break ;
77+ end = strstr (cursor , "\n" );
78+ memcpy (out_name , cursor , end - cursor );
79+ out_name [end - cursor ] = '\0' ;
80+
81+ cursor = strstr (out_name , ":" );
82+ if (cursor )
83+ * cursor = '/' ;
84+ else {
85+ sprintf (container , "%s:" , monitor_name );
86+ if (strstr (available_monitors , container ))
87+ config_is_container = 1 ;
88+ }
89+
90+ out_free :
91+ free (available_monitors );
92+ return retval ;
93+ }
94+
4795/*
4896 * ikm_read_enable - reads monitor's enable status
4997 *
@@ -137,7 +185,17 @@ static char *ikm_read_desc(char *monitor_name)
137185static int ikm_fill_monitor_definition (char * name , struct monitor * ikm )
138186{
139187 int enabled ;
140- char * desc ;
188+ char * desc , * nested_name ;
189+
190+ nested_name = strstr (name , ":" );
191+ if (nested_name ) {
192+ * nested_name = '/' ;
193+ ++ nested_name ;
194+ ikm -> nested = 1 ;
195+ } else {
196+ nested_name = name ;
197+ ikm -> nested = 0 ;
198+ }
141199
142200 enabled = ikm_read_enable (name );
143201 if (enabled < 0 ) {
@@ -151,7 +209,7 @@ static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
151209 return -1 ;
152210 }
153211
154- strncpy (ikm -> name , name , MAX_DA_NAME_LEN );
212+ strncpy (ikm -> name , nested_name , MAX_DA_NAME_LEN );
155213 ikm -> enabled = enabled ;
156214 strncpy (ikm -> desc , desc , MAX_DESCRIPTION );
157215
@@ -273,7 +331,7 @@ static int ikm_has_id(char *monitor_name)
273331int ikm_list_monitors (void )
274332{
275333 char * available_monitors ;
276- struct monitor ikm ;
334+ struct monitor ikm = { 0 } ;
277335 char * curr , * next ;
278336 int retval ;
279337
@@ -293,7 +351,9 @@ int ikm_list_monitors(void)
293351 if (retval )
294352 err_msg ("ikm: error reading %d in kernel monitor, skipping\n" , curr );
295353
296- printf ("%-24s %s %s\n" , ikm .name , ikm .desc , ikm .enabled ? "[ON]" : "[OFF]" );
354+ printf ("%s%-*s %s %s\n" , ikm .nested ? " - " : "" ,
355+ ikm .nested ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN ,
356+ ikm .name , ikm .desc , ikm .enabled ? "[ON]" : "[OFF]" );
297357 curr = ++ next ;
298358
299359 } while (strlen (curr ));
@@ -343,11 +403,11 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
343403 unsigned long long final_state ;
344404 unsigned long long pid ;
345405 unsigned long long id ;
346- int cpu = record -> cpu ;
347406 int val ;
407+ bool missing_id ;
348408
349409 if (config_has_id )
350- tep_get_field_val (s , trace_event , "id" , record , & id , 1 );
410+ missing_id = tep_get_field_val (s , trace_event , "id" , record , & id , 1 );
351411
352412 tep_get_common_field_val (s , trace_event , "common_pid" , record , & pid , 1 );
353413
@@ -356,12 +416,21 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
356416 else if (config_my_pid && (config_my_pid == pid ))
357417 return 0 ;
358418
359- tep_print_event (trace_event -> tep , s , record , "%16s-%-8d " , TEP_PRINT_COMM , TEP_PRINT_PID );
419+ tep_print_event (trace_event -> tep , s , record , "%16s-%-8d [%.3d] " ,
420+ TEP_PRINT_COMM , TEP_PRINT_PID , TEP_PRINT_CPU );
360421
361- trace_seq_printf (s , "[%.3d] event " , cpu );
422+ if (config_is_container )
423+ tep_print_event (trace_event -> tep , s , record , "%s " , TEP_PRINT_NAME );
424+ else
425+ trace_seq_printf (s , "event " );
362426
363- if (config_has_id )
364- trace_seq_printf (s , "%8llu " , id );
427+ if (config_has_id ) {
428+ if (missing_id )
429+ /* placeholder if we are dealing with a mixed-type container*/
430+ trace_seq_printf (s , " " );
431+ else
432+ trace_seq_printf (s , "%8llu " , id );
433+ }
365434
366435 state = tep_get_field_raw (s , trace_event , "state" , record , & val , 0 );
367436 event = tep_get_field_raw (s , trace_event , "event" , record , & val , 0 );
@@ -394,9 +463,10 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
394463 int cpu = record -> cpu ;
395464 char * state , * event ;
396465 int val ;
466+ bool missing_id ;
397467
398468 if (config_has_id )
399- tep_get_field_val (s , trace_event , "id" , record , & id , 1 );
469+ missing_id = tep_get_field_val (s , trace_event , "id" , record , & id , 1 );
400470
401471 tep_get_common_field_val (s , trace_event , "common_pid" , record , & pid , 1 );
402472
@@ -405,10 +475,20 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
405475 else if (config_my_pid == pid )
406476 return 0 ;
407477
408- trace_seq_printf (s , "%8lld [%03d] error " , pid , cpu );
478+ trace_seq_printf (s , "%8lld [%03d] " , pid , cpu );
409479
410- if (config_has_id )
411- trace_seq_printf (s , "%8llu " , id );
480+ if (config_is_container )
481+ tep_print_event (trace_event -> tep , s , record , "%s " , TEP_PRINT_NAME );
482+ else
483+ trace_seq_printf (s , "error " );
484+
485+ if (config_has_id ) {
486+ if (missing_id )
487+ /* placeholder if we are dealing with a mixed-type container*/
488+ trace_seq_printf (s , " " );
489+ else
490+ trace_seq_printf (s , "%8llu " , id );
491+ }
412492
413493 state = tep_get_field_raw (s , trace_event , "state" , record , & val , 0 );
414494 event = tep_get_field_raw (s , trace_event , "event" , record , & val , 0 );
@@ -421,6 +501,64 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
421501 return 0 ;
422502}
423503
504+ static int ikm_enable_trace_events (char * monitor_name , struct trace_instance * inst )
505+ {
506+ char event [MAX_DA_NAME_LEN + 7 ]; /* max(error_,event_) + '0' = 7 */
507+ int retval ;
508+
509+ snprintf (event , sizeof (event ), "event_%s" , monitor_name );
510+ retval = tracefs_event_enable (inst -> inst , "rv" , event );
511+ if (retval )
512+ return -1 ;
513+
514+ tep_register_event_handler (inst -> tep , -1 , "rv" , event ,
515+ ikm_event_handler , NULL );
516+
517+ snprintf (event , sizeof (event ), "error_%s" , monitor_name );
518+ retval = tracefs_event_enable (inst -> inst , "rv" , event );
519+ if (retval )
520+ return -1 ;
521+
522+ tep_register_event_handler (inst -> tep , -1 , "rv" , event ,
523+ ikm_error_handler , NULL );
524+
525+ /* set if at least 1 monitor has id in case of a container */
526+ config_has_id = ikm_has_id (monitor_name );
527+ if (config_has_id < 0 )
528+ return -1 ;
529+
530+
531+ return 0 ;
532+ }
533+
534+ static int ikm_enable_trace_container (char * monitor_name ,
535+ struct trace_instance * inst )
536+ {
537+ DIR * dp ;
538+ char * abs_path , rv_path [MAX_PATH ];
539+ struct dirent * ep ;
540+ int retval = 0 ;
541+
542+ snprintf (rv_path , MAX_PATH , "rv/monitors/%s" , monitor_name );
543+ abs_path = tracefs_instance_get_file (NULL , rv_path );
544+ if (!abs_path )
545+ return -1 ;
546+ dp = opendir (abs_path );
547+ if (!dp )
548+ goto out_free ;
549+
550+ while (!retval && (ep = readdir (dp ))) {
551+ if (ep -> d_type != DT_DIR || ep -> d_name [0 ] == '.' )
552+ continue ;
553+ retval = ikm_enable_trace_events (ep -> d_name , inst );
554+ }
555+
556+ closedir (dp );
557+ out_free :
558+ free (abs_path );
559+ return retval ;
560+ }
561+
424562/*
425563 * ikm_setup_trace_instance - set up a tracing instance to collect data
426564 *
@@ -430,19 +568,12 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
430568 */
431569static struct trace_instance * ikm_setup_trace_instance (char * monitor_name )
432570{
433- char event [MAX_DA_NAME_LEN + 7 ]; /* max(error_,event_) + '0' = 7 */
434571 struct trace_instance * inst ;
435572 int retval ;
436573
437574 if (!config_trace )
438575 return NULL ;
439576
440- config_has_id = ikm_has_id (monitor_name );
441- if (config_has_id < 0 ) {
442- err_msg ("ikm: failed to read monitor %s event format\n" , monitor_name );
443- goto out_err ;
444- }
445-
446577 /* alloc data */
447578 inst = calloc (1 , sizeof (* inst ));
448579 if (!inst ) {
@@ -454,23 +585,13 @@ static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
454585 if (retval )
455586 goto out_free ;
456587
457- /* enable events */
458- snprintf (event , sizeof (event ), "event_%s" , monitor_name );
459- retval = tracefs_event_enable (inst -> inst , "rv" , event );
460- if (retval )
461- goto out_inst ;
462-
463- tep_register_event_handler (inst -> tep , -1 , "rv" , event ,
464- ikm_event_handler , NULL );
465-
466- snprintf (event , sizeof (event ), "error_%s" , monitor_name );
467- retval = tracefs_event_enable (inst -> inst , "rv" , event );
588+ if (config_is_container )
589+ retval = ikm_enable_trace_container (monitor_name , inst );
590+ else
591+ retval = ikm_enable_trace_events (monitor_name , inst );
468592 if (retval )
469593 goto out_inst ;
470594
471- tep_register_event_handler (inst -> tep , -1 , "rv" , event ,
472- ikm_error_handler , NULL );
473-
474595 /* ready to enable */
475596 tracefs_trace_on (inst -> inst );
476597
@@ -633,32 +754,41 @@ static int parse_arguments(char *monitor_name, int argc, char **argv)
633754int ikm_run_monitor (char * monitor_name , int argc , char * * argv )
634755{
635756 struct trace_instance * inst = NULL ;
757+ char * nested_name , full_name [2 * MAX_DA_NAME_LEN ];
636758 int retval ;
637759
638- /*
639- * Check if monitor exists by seeing it is enabled.
640- */
641- retval = __ikm_read_enable (monitor_name );
642- if (retval < 0 )
760+ nested_name = strstr (monitor_name , ":" );
761+ if (nested_name )
762+ ++ nested_name ;
763+ else
764+ nested_name = monitor_name ;
765+
766+ retval = __ikm_find_monitor_name (monitor_name , full_name );
767+ if (!retval )
643768 return 0 ;
769+ if (retval < 0 ) {
770+ err_msg ("ikm: error finding monitor %s\n" , nested_name );
771+ return -1 ;
772+ }
644773
774+ retval = __ikm_read_enable (full_name );
645775 if (retval ) {
646- err_msg ("ikm: monitor %s (in-kernel) is already enabled\n" , monitor_name );
776+ err_msg ("ikm: monitor %s (in-kernel) is already enabled\n" , nested_name );
647777 return -1 ;
648778 }
649779
650780 /* we should be good to go */
651- retval = parse_arguments (monitor_name , argc , argv );
781+ retval = parse_arguments (full_name , argc , argv );
652782 if (retval )
653- ikm_usage (1 , monitor_name , "ikm: failed parsing arguments" );
783+ ikm_usage (1 , nested_name , "ikm: failed parsing arguments" );
654784
655785 if (config_trace ) {
656- inst = ikm_setup_trace_instance (monitor_name );
786+ inst = ikm_setup_trace_instance (nested_name );
657787 if (!inst )
658788 return -1 ;
659789 }
660790
661- retval = ikm_enable (monitor_name );
791+ retval = ikm_enable (full_name );
662792 if (retval < 0 )
663793 goto out_free_instance ;
664794
@@ -682,17 +812,17 @@ int ikm_run_monitor(char *monitor_name, int argc, char **argv)
682812 sleep (1 );
683813 }
684814
685- ikm_disable (monitor_name );
815+ ikm_disable (full_name );
686816 ikm_destroy_trace_instance (inst );
687817
688818 if (config_reactor && config_initial_reactor )
689- ikm_write_reactor (monitor_name , config_initial_reactor );
819+ ikm_write_reactor (full_name , config_initial_reactor );
690820
691821 return 1 ;
692822
693823out_free_instance :
694824 ikm_destroy_trace_instance (inst );
695825 if (config_reactor && config_initial_reactor )
696- ikm_write_reactor (monitor_name , config_initial_reactor );
826+ ikm_write_reactor (full_name , config_initial_reactor );
697827 return -1 ;
698828}
0 commit comments