Skip to content

Commit b3b1e6e

Browse files
committed
ftrace: Create set_ftrace_notrace_pid to not trace tasks
There's currently a way to select a task that should only be traced by functions, but there's no way to select a task not to be traced by the function tracer. Add a set_ftrace_notrace_pid file that acts the same as set_ftrace_pid (and is also affected by function-fork), but the task pids in this file will not be traced even if they are listed in the set_ftrace_pid file. This makes it easy for tools like trace-cmd to "hide" itself from the function tracer when it is recording other tasks. Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 717e3f5 commit b3b1e6e

File tree

4 files changed

+180
-35
lines changed

4 files changed

+180
-35
lines changed

kernel/trace/ftrace.c

Lines changed: 158 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ static bool ftrace_pids_enabled(struct ftrace_ops *ops)
102102

103103
tr = ops->private;
104104

105-
return tr->function_pids != NULL;
105+
return tr->function_pids != NULL || tr->function_no_pids != NULL;
106106
}
107107

108108
static void ftrace_update_trampoline(struct ftrace_ops *ops);
@@ -6931,10 +6931,12 @@ ftrace_filter_pid_sched_switch_probe(void *data, bool preempt,
69316931
{
69326932
struct trace_array *tr = data;
69336933
struct trace_pid_list *pid_list;
6934+
struct trace_pid_list *no_pid_list;
69346935

69356936
pid_list = rcu_dereference_sched(tr->function_pids);
6937+
no_pid_list = rcu_dereference_sched(tr->function_no_pids);
69366938

6937-
if (trace_ignore_this_task(pid_list, next))
6939+
if (trace_ignore_this_task(pid_list, no_pid_list, next))
69386940
this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid,
69396941
FTRACE_PID_IGNORE);
69406942
else
@@ -6952,6 +6954,9 @@ ftrace_pid_follow_sched_process_fork(void *data,
69526954

69536955
pid_list = rcu_dereference_sched(tr->function_pids);
69546956
trace_filter_add_remove_task(pid_list, self, task);
6957+
6958+
pid_list = rcu_dereference_sched(tr->function_no_pids);
6959+
trace_filter_add_remove_task(pid_list, self, task);
69556960
}
69566961

69576962
static void
@@ -6962,6 +6967,9 @@ ftrace_pid_follow_sched_process_exit(void *data, struct task_struct *task)
69626967

69636968
pid_list = rcu_dereference_sched(tr->function_pids);
69646969
trace_filter_add_remove_task(pid_list, NULL, task);
6970+
6971+
pid_list = rcu_dereference_sched(tr->function_no_pids);
6972+
trace_filter_add_remove_task(pid_list, NULL, task);
69656973
}
69666974

69676975
void ftrace_pid_follow_fork(struct trace_array *tr, bool enable)
@@ -6979,42 +6987,64 @@ void ftrace_pid_follow_fork(struct trace_array *tr, bool enable)
69796987
}
69806988
}
69816989

6982-
static void clear_ftrace_pids(struct trace_array *tr)
6990+
enum {
6991+
TRACE_PIDS = BIT(0),
6992+
TRACE_NO_PIDS = BIT(1),
6993+
};
6994+
6995+
static void clear_ftrace_pids(struct trace_array *tr, int type)
69836996
{
69846997
struct trace_pid_list *pid_list;
6998+
struct trace_pid_list *no_pid_list;
69856999
int cpu;
69867000

69877001
pid_list = rcu_dereference_protected(tr->function_pids,
69887002
lockdep_is_held(&ftrace_lock));
6989-
if (!pid_list)
7003+
no_pid_list = rcu_dereference_protected(tr->function_no_pids,
7004+
lockdep_is_held(&ftrace_lock));
7005+
7006+
/* Make sure there's something to do */
7007+
if (!(((type & TRACE_PIDS) && pid_list) ||
7008+
((type & TRACE_NO_PIDS) && no_pid_list)))
69907009
return;
69917010

6992-
unregister_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);
7011+
/* See if the pids still need to be checked after this */
7012+
if (!((!(type & TRACE_PIDS) && pid_list) ||
7013+
(!(type & TRACE_NO_PIDS) && no_pid_list))) {
7014+
unregister_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);
7015+
for_each_possible_cpu(cpu)
7016+
per_cpu_ptr(tr->array_buffer.data, cpu)->ftrace_ignore_pid = FTRACE_PID_TRACE;
7017+
}
69937018

6994-
for_each_possible_cpu(cpu)
6995-
per_cpu_ptr(tr->array_buffer.data, cpu)->ftrace_ignore_pid = FTRACE_PID_TRACE;
7019+
if (type & TRACE_PIDS)
7020+
rcu_assign_pointer(tr->function_pids, NULL);
69967021

6997-
rcu_assign_pointer(tr->function_pids, NULL);
7022+
if (type & TRACE_NO_PIDS)
7023+
rcu_assign_pointer(tr->function_no_pids, NULL);
69987024

69997025
/* Wait till all users are no longer using pid filtering */
70007026
synchronize_rcu();
70017027

7002-
trace_free_pid_list(pid_list);
7028+
if ((type & TRACE_PIDS) && pid_list)
7029+
trace_free_pid_list(pid_list);
7030+
7031+
if ((type & TRACE_NO_PIDS) && no_pid_list)
7032+
trace_free_pid_list(no_pid_list);
70037033
}
70047034

70057035
void ftrace_clear_pids(struct trace_array *tr)
70067036
{
70077037
mutex_lock(&ftrace_lock);
70087038

7009-
clear_ftrace_pids(tr);
7039+
clear_ftrace_pids(tr, TRACE_PIDS | TRACE_NO_PIDS);
70107040

70117041
mutex_unlock(&ftrace_lock);
70127042
}
70137043

7014-
static void ftrace_pid_reset(struct trace_array *tr)
7044+
static void ftrace_pid_reset(struct trace_array *tr, int type)
70157045
{
70167046
mutex_lock(&ftrace_lock);
7017-
clear_ftrace_pids(tr);
7047+
clear_ftrace_pids(tr, type);
70187048

70197049
ftrace_update_pid_func();
70207050
ftrace_startup_all(0);
@@ -7078,9 +7108,45 @@ static const struct seq_operations ftrace_pid_sops = {
70787108
.show = fpid_show,
70797109
};
70807110

7081-
static int
7082-
ftrace_pid_open(struct inode *inode, struct file *file)
7111+
static void *fnpid_start(struct seq_file *m, loff_t *pos)
7112+
__acquires(RCU)
7113+
{
7114+
struct trace_pid_list *pid_list;
7115+
struct trace_array *tr = m->private;
7116+
7117+
mutex_lock(&ftrace_lock);
7118+
rcu_read_lock_sched();
7119+
7120+
pid_list = rcu_dereference_sched(tr->function_no_pids);
7121+
7122+
if (!pid_list)
7123+
return !(*pos) ? FTRACE_NO_PIDS : NULL;
7124+
7125+
return trace_pid_start(pid_list, pos);
7126+
}
7127+
7128+
static void *fnpid_next(struct seq_file *m, void *v, loff_t *pos)
70837129
{
7130+
struct trace_array *tr = m->private;
7131+
struct trace_pid_list *pid_list = rcu_dereference_sched(tr->function_no_pids);
7132+
7133+
if (v == FTRACE_NO_PIDS) {
7134+
(*pos)++;
7135+
return NULL;
7136+
}
7137+
return trace_pid_next(pid_list, v, pos);
7138+
}
7139+
7140+
static const struct seq_operations ftrace_no_pid_sops = {
7141+
.start = fnpid_start,
7142+
.next = fnpid_next,
7143+
.stop = fpid_stop,
7144+
.show = fpid_show,
7145+
};
7146+
7147+
static int pid_open(struct inode *inode, struct file *file, int type)
7148+
{
7149+
const struct seq_operations *seq_ops;
70847150
struct trace_array *tr = inode->i_private;
70857151
struct seq_file *m;
70867152
int ret = 0;
@@ -7091,9 +7157,18 @@ ftrace_pid_open(struct inode *inode, struct file *file)
70917157

70927158
if ((file->f_mode & FMODE_WRITE) &&
70937159
(file->f_flags & O_TRUNC))
7094-
ftrace_pid_reset(tr);
7160+
ftrace_pid_reset(tr, type);
7161+
7162+
switch (type) {
7163+
case TRACE_PIDS:
7164+
seq_ops = &ftrace_pid_sops;
7165+
break;
7166+
case TRACE_NO_PIDS:
7167+
seq_ops = &ftrace_no_pid_sops;
7168+
break;
7169+
}
70957170

7096-
ret = seq_open(file, &ftrace_pid_sops);
7171+
ret = seq_open(file, seq_ops);
70977172
if (ret < 0) {
70987173
trace_array_put(tr);
70997174
} else {
@@ -7105,19 +7180,34 @@ ftrace_pid_open(struct inode *inode, struct file *file)
71057180
return ret;
71067181
}
71077182

7183+
static int
7184+
ftrace_pid_open(struct inode *inode, struct file *file)
7185+
{
7186+
return pid_open(inode, file, TRACE_PIDS);
7187+
}
7188+
7189+
static int
7190+
ftrace_no_pid_open(struct inode *inode, struct file *file)
7191+
{
7192+
return pid_open(inode, file, TRACE_NO_PIDS);
7193+
}
7194+
71087195
static void ignore_task_cpu(void *data)
71097196
{
71107197
struct trace_array *tr = data;
71117198
struct trace_pid_list *pid_list;
7199+
struct trace_pid_list *no_pid_list;
71127200

71137201
/*
71147202
* This function is called by on_each_cpu() while the
71157203
* event_mutex is held.
71167204
*/
71177205
pid_list = rcu_dereference_protected(tr->function_pids,
71187206
mutex_is_locked(&ftrace_lock));
7207+
no_pid_list = rcu_dereference_protected(tr->function_no_pids,
7208+
mutex_is_locked(&ftrace_lock));
71197209

7120-
if (trace_ignore_this_task(pid_list, current))
7210+
if (trace_ignore_this_task(pid_list, no_pid_list, current))
71217211
this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid,
71227212
FTRACE_PID_IGNORE);
71237213
else
@@ -7126,12 +7216,13 @@ static void ignore_task_cpu(void *data)
71267216
}
71277217

71287218
static ssize_t
7129-
ftrace_pid_write(struct file *filp, const char __user *ubuf,
7130-
size_t cnt, loff_t *ppos)
7219+
pid_write(struct file *filp, const char __user *ubuf,
7220+
size_t cnt, loff_t *ppos, int type)
71317221
{
71327222
struct seq_file *m = filp->private_data;
71337223
struct trace_array *tr = m->private;
7134-
struct trace_pid_list *filtered_pids = NULL;
7224+
struct trace_pid_list *filtered_pids;
7225+
struct trace_pid_list *other_pids;
71357226
struct trace_pid_list *pid_list;
71367227
ssize_t ret;
71377228

@@ -7140,19 +7231,39 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf,
71407231

71417232
mutex_lock(&ftrace_lock);
71427233

7143-
filtered_pids = rcu_dereference_protected(tr->function_pids,
7234+
switch (type) {
7235+
case TRACE_PIDS:
7236+
filtered_pids = rcu_dereference_protected(tr->function_pids,
71447237
lockdep_is_held(&ftrace_lock));
7238+
other_pids = rcu_dereference_protected(tr->function_no_pids,
7239+
lockdep_is_held(&ftrace_lock));
7240+
break;
7241+
case TRACE_NO_PIDS:
7242+
filtered_pids = rcu_dereference_protected(tr->function_no_pids,
7243+
lockdep_is_held(&ftrace_lock));
7244+
other_pids = rcu_dereference_protected(tr->function_pids,
7245+
lockdep_is_held(&ftrace_lock));
7246+
break;
7247+
}
71457248

71467249
ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt);
71477250
if (ret < 0)
71487251
goto out;
71497252

7150-
rcu_assign_pointer(tr->function_pids, pid_list);
7253+
switch (type) {
7254+
case TRACE_PIDS:
7255+
rcu_assign_pointer(tr->function_pids, pid_list);
7256+
break;
7257+
case TRACE_NO_PIDS:
7258+
rcu_assign_pointer(tr->function_no_pids, pid_list);
7259+
break;
7260+
}
7261+
71517262

71527263
if (filtered_pids) {
71537264
synchronize_rcu();
71547265
trace_free_pid_list(filtered_pids);
7155-
} else if (pid_list) {
7266+
} else if (pid_list && !other_pids) {
71567267
/* Register a probe to set whether to ignore the tracing of a task */
71577268
register_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);
71587269
}
@@ -7175,6 +7286,20 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf,
71757286
return ret;
71767287
}
71777288

7289+
static ssize_t
7290+
ftrace_pid_write(struct file *filp, const char __user *ubuf,
7291+
size_t cnt, loff_t *ppos)
7292+
{
7293+
return pid_write(filp, ubuf, cnt, ppos, TRACE_PIDS);
7294+
}
7295+
7296+
static ssize_t
7297+
ftrace_no_pid_write(struct file *filp, const char __user *ubuf,
7298+
size_t cnt, loff_t *ppos)
7299+
{
7300+
return pid_write(filp, ubuf, cnt, ppos, TRACE_NO_PIDS);
7301+
}
7302+
71787303
static int
71797304
ftrace_pid_release(struct inode *inode, struct file *file)
71807305
{
@@ -7193,10 +7318,20 @@ static const struct file_operations ftrace_pid_fops = {
71937318
.release = ftrace_pid_release,
71947319
};
71957320

7321+
static const struct file_operations ftrace_no_pid_fops = {
7322+
.open = ftrace_no_pid_open,
7323+
.write = ftrace_no_pid_write,
7324+
.read = seq_read,
7325+
.llseek = tracing_lseek,
7326+
.release = ftrace_pid_release,
7327+
};
7328+
71967329
void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer)
71977330
{
71987331
trace_create_file("set_ftrace_pid", 0644, d_tracer,
71997332
tr, &ftrace_pid_fops);
7333+
trace_create_file("set_ftrace_notrace_pid", 0644, d_tracer,
7334+
tr, &ftrace_no_pid_fops);
72007335
}
72017336

72027337
void __init ftrace_init_tracefs_toplevel(struct trace_array *tr,

kernel/trace/trace.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,16 +386,22 @@ trace_find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
386386
* Returns false if @task should be traced.
387387
*/
388388
bool
389-
trace_ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
389+
trace_ignore_this_task(struct trace_pid_list *filtered_pids,
390+
struct trace_pid_list *filtered_no_pids,
391+
struct task_struct *task)
390392
{
391393
/*
392-
* Return false, because if filtered_pids does not exist,
393-
* all pids are good to trace.
394+
* If filterd_no_pids is not empty, and the task's pid is listed
395+
* in filtered_no_pids, then return true.
396+
* Otherwise, if filtered_pids is empty, that means we can
397+
* trace all tasks. If it has content, then only trace pids
398+
* within filtered_pids.
394399
*/
395-
if (!filtered_pids)
396-
return false;
397400

398-
return !trace_find_filtered_pid(filtered_pids, task->pid);
401+
return (filtered_pids &&
402+
!trace_find_filtered_pid(filtered_pids, task->pid)) ||
403+
(filtered_no_pids &&
404+
trace_find_filtered_pid(filtered_no_pids, task->pid));
399405
}
400406

401407
/**
@@ -5013,6 +5019,8 @@ static const char readme_msg[] =
50135019
#ifdef CONFIG_FUNCTION_TRACER
50145020
" set_ftrace_pid\t- Write pid(s) to only function trace those pids\n"
50155021
"\t\t (function)\n"
5022+
" set_ftrace_notrace_pid\t- Write pid(s) to not function trace those pids\n"
5023+
"\t\t (function)\n"
50165024
#endif
50175025
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
50185026
" set_graph_function\t- Trace the nested calls of a function (function_graph)\n"

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ struct trace_array {
331331
#ifdef CONFIG_FUNCTION_TRACER
332332
struct ftrace_ops *ops;
333333
struct trace_pid_list __rcu *function_pids;
334+
struct trace_pid_list __rcu *function_no_pids;
334335
#ifdef CONFIG_DYNAMIC_FTRACE
335336
/* All of these are protected by the ftrace_lock */
336337
struct list_head func_probes;
@@ -782,6 +783,7 @@ extern int pid_max;
782783
bool trace_find_filtered_pid(struct trace_pid_list *filtered_pids,
783784
pid_t search_pid);
784785
bool trace_ignore_this_task(struct trace_pid_list *filtered_pids,
786+
struct trace_pid_list *filtered_no_pids,
785787
struct task_struct *task);
786788
void trace_filter_add_remove_task(struct trace_pid_list *pid_list,
787789
struct task_struct *self,

0 commit comments

Comments
 (0)