Skip to content

Commit c37775d

Browse files
committed
tracing: Add infrastructure to allow set_event_pid to follow children
Add the infrastructure needed to have the PIDs in set_event_pid to automatically add PIDs of the children of the tasks that have their PIDs in set_event_pid. This will also remove PIDs from set_event_pid when a task exits This is implemented by adding hooks into the fork and exit tracepoints. On fork, the PIDs are added to the list, and on exit, they are removed. Add a new option called event_fork that when set, PIDs in set_event_pid will automatically get their children PIDs added when they fork, as well as any task that exits will have its PID removed from set_event_pid. This works for instances as well. Signed-off-by: Steven Rostedt <[email protected]>
1 parent f4d34a8 commit c37775d

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

kernel/trace/trace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3571,6 +3571,9 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
35713571
if (mask == TRACE_ITER_RECORD_CMD)
35723572
trace_event_enable_cmd_record(enabled);
35733573

3574+
if (mask == TRACE_ITER_EVENT_FORK)
3575+
trace_event_follow_fork(tr, enabled);
3576+
35743577
if (mask == TRACE_ITER_OVERWRITE) {
35753578
ring_buffer_change_overwrite(tr->trace_buffer.buffer, enabled);
35763579
#ifdef CONFIG_TRACER_MAX_TRACE

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ static inline void __trace_stack(struct trace_array *tr, unsigned long flags,
655655
extern cycle_t ftrace_now(int cpu);
656656

657657
extern void trace_find_cmdline(int pid, char comm[]);
658+
extern void trace_event_follow_fork(struct trace_array *tr, bool enable);
658659

659660
#ifdef CONFIG_DYNAMIC_FTRACE
660661
extern unsigned long ftrace_update_tot_cnt;
@@ -966,6 +967,7 @@ extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
966967
C(STOP_ON_FREE, "disable_on_free"), \
967968
C(IRQ_INFO, "irq-info"), \
968969
C(MARKERS, "markers"), \
970+
C(EVENT_FORK, "event-fork"), \
969971
FUNCTION_FLAGS \
970972
FGRAPH_FLAGS \
971973
STACK_FLAGS \

kernel/trace/trace_events.c

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -474,28 +474,92 @@ static void ftrace_clear_events(struct trace_array *tr)
474474
/* Shouldn't this be in a header? */
475475
extern int pid_max;
476476

477+
/* Returns true if found in filter */
477478
static bool
478-
ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
479+
find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
479480
{
480-
pid_t pid;
481+
/*
482+
* If pid_max changed after filtered_pids was created, we
483+
* by default ignore all pids greater than the previous pid_max.
484+
*/
485+
if (search_pid >= filtered_pids->pid_max)
486+
return false;
487+
488+
return test_bit(search_pid, filtered_pids->pids);
489+
}
481490

491+
static bool
492+
ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
493+
{
482494
/*
483495
* Return false, because if filtered_pids does not exist,
484496
* all pids are good to trace.
485497
*/
486498
if (!filtered_pids)
487499
return false;
488500

489-
pid = task->pid;
501+
return !find_filtered_pid(filtered_pids, task->pid);
502+
}
490503

491-
/*
492-
* If pid_max changed after filtered_pids was created, we
493-
* by default ignore all pids greater than the previous pid_max.
494-
*/
495-
if (task->pid >= filtered_pids->pid_max)
496-
return true;
504+
static void filter_add_remove_task(struct trace_pid_list *pid_list,
505+
struct task_struct *self,
506+
struct task_struct *task)
507+
{
508+
if (!pid_list)
509+
return;
510+
511+
/* For forks, we only add if the forking task is listed */
512+
if (self) {
513+
if (!find_filtered_pid(pid_list, self->pid))
514+
return;
515+
}
516+
517+
/* Sorry, but we don't support pid_max changing after setting */
518+
if (task->pid >= pid_list->pid_max)
519+
return;
520+
521+
/* "self" is set for forks, and NULL for exits */
522+
if (self)
523+
set_bit(task->pid, pid_list->pids);
524+
else
525+
clear_bit(task->pid, pid_list->pids);
526+
}
527+
528+
static void
529+
event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
530+
{
531+
struct trace_pid_list *pid_list;
532+
struct trace_array *tr = data;
533+
534+
pid_list = rcu_dereference_sched(tr->filtered_pids);
535+
filter_add_remove_task(pid_list, NULL, task);
536+
}
497537

498-
return !test_bit(task->pid, filtered_pids->pids);
538+
static void
539+
event_filter_pid_sched_process_fork(void *data,
540+
struct task_struct *self,
541+
struct task_struct *task)
542+
{
543+
struct trace_pid_list *pid_list;
544+
struct trace_array *tr = data;
545+
546+
pid_list = rcu_dereference_sched(tr->filtered_pids);
547+
filter_add_remove_task(pid_list, self, task);
548+
}
549+
550+
void trace_event_follow_fork(struct trace_array *tr, bool enable)
551+
{
552+
if (enable) {
553+
register_trace_prio_sched_process_fork(event_filter_pid_sched_process_fork,
554+
tr, INT_MIN);
555+
register_trace_prio_sched_process_exit(event_filter_pid_sched_process_exit,
556+
tr, INT_MAX);
557+
} else {
558+
unregister_trace_sched_process_fork(event_filter_pid_sched_process_fork,
559+
tr);
560+
unregister_trace_sched_process_exit(event_filter_pid_sched_process_exit,
561+
tr);
562+
}
499563
}
500564

501565
static void

0 commit comments

Comments
 (0)