mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	tracing: Allow triggers to filter for CPU ids and process names
By extending the filter rules by more generic fields we can write triggers filters like echo 'stacktrace if cpu == 1' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger or echo 'stacktrace if comm == sshd' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger CPU and COMM are not part of struct trace_entry. We could add the two new fields to ftrace_common_field list and fix up all depending sides. But that looks pretty ugly. Another thing I would like to avoid that the 'format' file contents changes. All this can be avoided by introducing another list which contains non field members of struct trace_entry. Link: http://lkml.kernel.org/r/1439210146-24707-1-git-send-email-daniel.wagner@bmw-carit.de Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									c93bf928fe
								
							
						
					
					
						commit
						9f61668073
					
				
					 2 changed files with 77 additions and 2 deletions
				
			
		|  | @ -30,6 +30,7 @@ | |||
| DEFINE_MUTEX(event_mutex); | ||||
| 
 | ||||
| LIST_HEAD(ftrace_events); | ||||
| static LIST_HEAD(ftrace_generic_fields); | ||||
| static LIST_HEAD(ftrace_common_fields); | ||||
| 
 | ||||
| #define GFP_TRACE (GFP_KERNEL | __GFP_ZERO) | ||||
|  | @ -94,6 +95,10 @@ trace_find_event_field(struct trace_event_call *call, char *name) | |||
| 	struct ftrace_event_field *field; | ||||
| 	struct list_head *head; | ||||
| 
 | ||||
| 	field = __find_event_field(&ftrace_generic_fields, name); | ||||
| 	if (field) | ||||
| 		return field; | ||||
| 
 | ||||
| 	field = __find_event_field(&ftrace_common_fields, name); | ||||
| 	if (field) | ||||
| 		return field; | ||||
|  | @ -144,6 +149,13 @@ int trace_define_field(struct trace_event_call *call, const char *type, | |||
| } | ||||
| EXPORT_SYMBOL_GPL(trace_define_field); | ||||
| 
 | ||||
| #define __generic_field(type, item, filter_type)			\ | ||||
| 	ret = __trace_define_field(&ftrace_generic_fields, #type,	\ | ||||
| 				   #item, 0, 0, is_signed_type(type),	\ | ||||
| 				   filter_type);			\ | ||||
| 	if (ret)							\ | ||||
| 		return ret; | ||||
| 
 | ||||
| #define __common_field(type, item)					\ | ||||
| 	ret = __trace_define_field(&ftrace_common_fields, #type,	\ | ||||
| 				   "common_" #item,			\ | ||||
|  | @ -153,6 +165,16 @@ EXPORT_SYMBOL_GPL(trace_define_field); | |||
| 	if (ret)							\ | ||||
| 		return ret; | ||||
| 
 | ||||
| static int trace_define_generic_fields(void) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	__generic_field(int, cpu, FILTER_OTHER); | ||||
| 	__generic_field(char *, comm, FILTER_PTR_STRING); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int trace_define_common_fields(void) | ||||
| { | ||||
| 	int ret; | ||||
|  | @ -2671,6 +2693,9 @@ static __init int event_trace_init(void) | |||
| 	if (!entry) | ||||
| 		pr_warn("Could not create tracefs 'available_events' entry\n"); | ||||
| 
 | ||||
| 	if (trace_define_generic_fields()) | ||||
| 		pr_warn("tracing: Failed to allocated generic fields"); | ||||
| 
 | ||||
| 	if (trace_define_common_fields()) | ||||
| 		pr_warn("tracing: Failed to allocate common fields"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -252,6 +252,50 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event) | |||
| 	return match; | ||||
| } | ||||
| 
 | ||||
| /* Filter predicate for CPUs. */ | ||||
| static int filter_pred_cpu(struct filter_pred *pred, void *event) | ||||
| { | ||||
| 	int cpu, cmp; | ||||
| 	int match = 0; | ||||
| 
 | ||||
| 	cpu = raw_smp_processor_id(); | ||||
| 	cmp = pred->val; | ||||
| 
 | ||||
| 	switch (pred->op) { | ||||
| 	case OP_EQ: | ||||
| 		match = cpu == cmp; | ||||
| 		break; | ||||
| 	case OP_LT: | ||||
| 		match = cpu < cmp; | ||||
| 		break; | ||||
| 	case OP_LE: | ||||
| 		match = cpu <= cmp; | ||||
| 		break; | ||||
| 	case OP_GT: | ||||
| 		match = cpu > cmp; | ||||
| 		break; | ||||
| 	case OP_GE: | ||||
| 		match = cpu >= cmp; | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return !!match == !pred->not; | ||||
| } | ||||
| 
 | ||||
| /* Filter predicate for COMM. */ | ||||
| static int filter_pred_comm(struct filter_pred *pred, void *event) | ||||
| { | ||||
| 	int cmp, match; | ||||
| 
 | ||||
| 	cmp = pred->regex.match(current->comm, &pred->regex, | ||||
| 				pred->regex.field_len); | ||||
| 	match = cmp ^ pred->not; | ||||
| 
 | ||||
| 	return match; | ||||
| } | ||||
| 
 | ||||
| static int filter_pred_none(struct filter_pred *pred, void *event) | ||||
| { | ||||
| 	return 0; | ||||
|  | @ -1002,7 +1046,10 @@ static int init_pred(struct filter_parse_state *ps, | |||
| 	if (is_string_field(field)) { | ||||
| 		filter_build_regex(pred); | ||||
| 
 | ||||
| 		if (field->filter_type == FILTER_STATIC_STRING) { | ||||
| 		if (!strcmp(field->name, "comm")) { | ||||
| 			fn = filter_pred_comm; | ||||
| 			pred->regex.field_len = TASK_COMM_LEN; | ||||
| 		} else if (field->filter_type == FILTER_STATIC_STRING) { | ||||
| 			fn = filter_pred_string; | ||||
| 			pred->regex.field_len = field->size; | ||||
| 		} else if (field->filter_type == FILTER_DYN_STRING) | ||||
|  | @ -1025,6 +1072,9 @@ static int init_pred(struct filter_parse_state *ps, | |||
| 		} | ||||
| 		pred->val = val; | ||||
| 
 | ||||
| 		if (!strcmp(field->name, "cpu")) | ||||
| 			fn = filter_pred_cpu; | ||||
| 		else | ||||
| 			fn = select_comparison_fn(pred->op, field->size, | ||||
| 					  field->is_signed); | ||||
| 		if (!fn) { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Daniel Wagner
						Daniel Wagner