xref: /linux/kernel/trace/trace_pid.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*98021e37SSteven Rostedt // SPDX-License-Identifier: GPL-2.0
2*98021e37SSteven Rostedt 
3*98021e37SSteven Rostedt #include "trace.h"
4*98021e37SSteven Rostedt 
5*98021e37SSteven Rostedt /**
6*98021e37SSteven Rostedt  * trace_find_filtered_pid - check if a pid exists in a filtered_pid list
7*98021e37SSteven Rostedt  * @filtered_pids: The list of pids to check
8*98021e37SSteven Rostedt  * @search_pid: The PID to find in @filtered_pids
9*98021e37SSteven Rostedt  *
10*98021e37SSteven Rostedt  * Returns true if @search_pid is found in @filtered_pids, and false otherwise.
11*98021e37SSteven Rostedt  */
12*98021e37SSteven Rostedt bool
13*98021e37SSteven Rostedt trace_find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
14*98021e37SSteven Rostedt {
15*98021e37SSteven Rostedt 	return trace_pid_list_is_set(filtered_pids, search_pid);
16*98021e37SSteven Rostedt }
17*98021e37SSteven Rostedt 
18*98021e37SSteven Rostedt /**
19*98021e37SSteven Rostedt  * trace_ignore_this_task - should a task be ignored for tracing
20*98021e37SSteven Rostedt  * @filtered_pids: The list of pids to check
21*98021e37SSteven Rostedt  * @filtered_no_pids: The list of pids not to be traced
22*98021e37SSteven Rostedt  * @task: The task that should be ignored if not filtered
23*98021e37SSteven Rostedt  *
24*98021e37SSteven Rostedt  * Checks if @task should be traced or not from @filtered_pids.
25*98021e37SSteven Rostedt  * Returns true if @task should *NOT* be traced.
26*98021e37SSteven Rostedt  * Returns false if @task should be traced.
27*98021e37SSteven Rostedt  */
28*98021e37SSteven Rostedt bool
29*98021e37SSteven Rostedt trace_ignore_this_task(struct trace_pid_list *filtered_pids,
30*98021e37SSteven Rostedt 		       struct trace_pid_list *filtered_no_pids,
31*98021e37SSteven Rostedt 		       struct task_struct *task)
32*98021e37SSteven Rostedt {
33*98021e37SSteven Rostedt 	/*
34*98021e37SSteven Rostedt 	 * If filtered_no_pids is not empty, and the task's pid is listed
35*98021e37SSteven Rostedt 	 * in filtered_no_pids, then return true.
36*98021e37SSteven Rostedt 	 * Otherwise, if filtered_pids is empty, that means we can
37*98021e37SSteven Rostedt 	 * trace all tasks. If it has content, then only trace pids
38*98021e37SSteven Rostedt 	 * within filtered_pids.
39*98021e37SSteven Rostedt 	 */
40*98021e37SSteven Rostedt 
41*98021e37SSteven Rostedt 	return (filtered_pids &&
42*98021e37SSteven Rostedt 		!trace_find_filtered_pid(filtered_pids, task->pid)) ||
43*98021e37SSteven Rostedt 		(filtered_no_pids &&
44*98021e37SSteven Rostedt 		 trace_find_filtered_pid(filtered_no_pids, task->pid));
45*98021e37SSteven Rostedt }
46*98021e37SSteven Rostedt 
47*98021e37SSteven Rostedt /**
48*98021e37SSteven Rostedt  * trace_filter_add_remove_task - Add or remove a task from a pid_list
49*98021e37SSteven Rostedt  * @pid_list: The list to modify
50*98021e37SSteven Rostedt  * @self: The current task for fork or NULL for exit
51*98021e37SSteven Rostedt  * @task: The task to add or remove
52*98021e37SSteven Rostedt  *
53*98021e37SSteven Rostedt  * If adding a task, if @self is defined, the task is only added if @self
54*98021e37SSteven Rostedt  * is also included in @pid_list. This happens on fork and tasks should
55*98021e37SSteven Rostedt  * only be added when the parent is listed. If @self is NULL, then the
56*98021e37SSteven Rostedt  * @task pid will be removed from the list, which would happen on exit
57*98021e37SSteven Rostedt  * of a task.
58*98021e37SSteven Rostedt  */
59*98021e37SSteven Rostedt void trace_filter_add_remove_task(struct trace_pid_list *pid_list,
60*98021e37SSteven Rostedt 				  struct task_struct *self,
61*98021e37SSteven Rostedt 				  struct task_struct *task)
62*98021e37SSteven Rostedt {
63*98021e37SSteven Rostedt 	if (!pid_list)
64*98021e37SSteven Rostedt 		return;
65*98021e37SSteven Rostedt 
66*98021e37SSteven Rostedt 	/* For forks, we only add if the forking task is listed */
67*98021e37SSteven Rostedt 	if (self) {
68*98021e37SSteven Rostedt 		if (!trace_find_filtered_pid(pid_list, self->pid))
69*98021e37SSteven Rostedt 			return;
70*98021e37SSteven Rostedt 	}
71*98021e37SSteven Rostedt 
72*98021e37SSteven Rostedt 	/* "self" is set for forks, and NULL for exits */
73*98021e37SSteven Rostedt 	if (self)
74*98021e37SSteven Rostedt 		trace_pid_list_set(pid_list, task->pid);
75*98021e37SSteven Rostedt 	else
76*98021e37SSteven Rostedt 		trace_pid_list_clear(pid_list, task->pid);
77*98021e37SSteven Rostedt }
78*98021e37SSteven Rostedt 
79*98021e37SSteven Rostedt /**
80*98021e37SSteven Rostedt  * trace_pid_next - Used for seq_file to get to the next pid of a pid_list
81*98021e37SSteven Rostedt  * @pid_list: The pid list to show
82*98021e37SSteven Rostedt  * @v: The last pid that was shown (+1 the actual pid to let zero be displayed)
83*98021e37SSteven Rostedt  * @pos: The position of the file
84*98021e37SSteven Rostedt  *
85*98021e37SSteven Rostedt  * This is used by the seq_file "next" operation to iterate the pids
86*98021e37SSteven Rostedt  * listed in a trace_pid_list structure.
87*98021e37SSteven Rostedt  *
88*98021e37SSteven Rostedt  * Returns the pid+1 as we want to display pid of zero, but NULL would
89*98021e37SSteven Rostedt  * stop the iteration.
90*98021e37SSteven Rostedt  */
91*98021e37SSteven Rostedt void *trace_pid_next(struct trace_pid_list *pid_list, void *v, loff_t *pos)
92*98021e37SSteven Rostedt {
93*98021e37SSteven Rostedt 	long pid = (unsigned long)v;
94*98021e37SSteven Rostedt 	unsigned int next;
95*98021e37SSteven Rostedt 
96*98021e37SSteven Rostedt 	(*pos)++;
97*98021e37SSteven Rostedt 
98*98021e37SSteven Rostedt 	/* pid already is +1 of the actual previous bit */
99*98021e37SSteven Rostedt 	if (trace_pid_list_next(pid_list, pid, &next) < 0)
100*98021e37SSteven Rostedt 		return NULL;
101*98021e37SSteven Rostedt 
102*98021e37SSteven Rostedt 	pid = next;
103*98021e37SSteven Rostedt 
104*98021e37SSteven Rostedt 	/* Return pid + 1 to allow zero to be represented */
105*98021e37SSteven Rostedt 	return (void *)(pid + 1);
106*98021e37SSteven Rostedt }
107*98021e37SSteven Rostedt 
108*98021e37SSteven Rostedt /**
109*98021e37SSteven Rostedt  * trace_pid_start - Used for seq_file to start reading pid lists
110*98021e37SSteven Rostedt  * @pid_list: The pid list to show
111*98021e37SSteven Rostedt  * @pos: The position of the file
112*98021e37SSteven Rostedt  *
113*98021e37SSteven Rostedt  * This is used by seq_file "start" operation to start the iteration
114*98021e37SSteven Rostedt  * of listing pids.
115*98021e37SSteven Rostedt  *
116*98021e37SSteven Rostedt  * Returns the pid+1 as we want to display pid of zero, but NULL would
117*98021e37SSteven Rostedt  * stop the iteration.
118*98021e37SSteven Rostedt  */
119*98021e37SSteven Rostedt void *trace_pid_start(struct trace_pid_list *pid_list, loff_t *pos)
120*98021e37SSteven Rostedt {
121*98021e37SSteven Rostedt 	unsigned long pid;
122*98021e37SSteven Rostedt 	unsigned int first;
123*98021e37SSteven Rostedt 	loff_t l = 0;
124*98021e37SSteven Rostedt 
125*98021e37SSteven Rostedt 	if (trace_pid_list_first(pid_list, &first) < 0)
126*98021e37SSteven Rostedt 		return NULL;
127*98021e37SSteven Rostedt 
128*98021e37SSteven Rostedt 	pid = first;
129*98021e37SSteven Rostedt 
130*98021e37SSteven Rostedt 	/* Return pid + 1 so that zero can be the exit value */
131*98021e37SSteven Rostedt 	for (pid++; pid && l < *pos;
132*98021e37SSteven Rostedt 	     pid = (unsigned long)trace_pid_next(pid_list, (void *)pid, &l))
133*98021e37SSteven Rostedt 		;
134*98021e37SSteven Rostedt 	return (void *)pid;
135*98021e37SSteven Rostedt }
136*98021e37SSteven Rostedt 
137*98021e37SSteven Rostedt /**
138*98021e37SSteven Rostedt  * trace_pid_show - show the current pid in seq_file processing
139*98021e37SSteven Rostedt  * @m: The seq_file structure to write into
140*98021e37SSteven Rostedt  * @v: A void pointer of the pid (+1) value to display
141*98021e37SSteven Rostedt  *
142*98021e37SSteven Rostedt  * Can be directly used by seq_file operations to display the current
143*98021e37SSteven Rostedt  * pid value.
144*98021e37SSteven Rostedt  */
145*98021e37SSteven Rostedt int trace_pid_show(struct seq_file *m, void *v)
146*98021e37SSteven Rostedt {
147*98021e37SSteven Rostedt 	unsigned long pid = (unsigned long)v - 1;
148*98021e37SSteven Rostedt 
149*98021e37SSteven Rostedt 	seq_printf(m, "%lu\n", pid);
150*98021e37SSteven Rostedt 	return 0;
151*98021e37SSteven Rostedt }
152*98021e37SSteven Rostedt 
153*98021e37SSteven Rostedt /* 128 should be much more than enough */
154*98021e37SSteven Rostedt #define PID_BUF_SIZE		127
155*98021e37SSteven Rostedt 
156*98021e37SSteven Rostedt int trace_pid_write(struct trace_pid_list *filtered_pids,
157*98021e37SSteven Rostedt 		    struct trace_pid_list **new_pid_list,
158*98021e37SSteven Rostedt 		    const char __user *ubuf, size_t cnt)
159*98021e37SSteven Rostedt {
160*98021e37SSteven Rostedt 	struct trace_pid_list *pid_list;
161*98021e37SSteven Rostedt 	struct trace_parser parser;
162*98021e37SSteven Rostedt 	unsigned long val;
163*98021e37SSteven Rostedt 	int nr_pids = 0;
164*98021e37SSteven Rostedt 	ssize_t read = 0;
165*98021e37SSteven Rostedt 	ssize_t ret;
166*98021e37SSteven Rostedt 	loff_t pos;
167*98021e37SSteven Rostedt 	pid_t pid;
168*98021e37SSteven Rostedt 
169*98021e37SSteven Rostedt 	if (trace_parser_get_init(&parser, PID_BUF_SIZE + 1))
170*98021e37SSteven Rostedt 		return -ENOMEM;
171*98021e37SSteven Rostedt 
172*98021e37SSteven Rostedt 	/*
173*98021e37SSteven Rostedt 	 * Always recreate a new array. The write is an all or nothing
174*98021e37SSteven Rostedt 	 * operation. Always create a new array when adding new pids by
175*98021e37SSteven Rostedt 	 * the user. If the operation fails, then the current list is
176*98021e37SSteven Rostedt 	 * not modified.
177*98021e37SSteven Rostedt 	 */
178*98021e37SSteven Rostedt 	pid_list = trace_pid_list_alloc();
179*98021e37SSteven Rostedt 	if (!pid_list) {
180*98021e37SSteven Rostedt 		trace_parser_put(&parser);
181*98021e37SSteven Rostedt 		return -ENOMEM;
182*98021e37SSteven Rostedt 	}
183*98021e37SSteven Rostedt 
184*98021e37SSteven Rostedt 	if (filtered_pids) {
185*98021e37SSteven Rostedt 		/* copy the current bits to the new max */
186*98021e37SSteven Rostedt 		ret = trace_pid_list_first(filtered_pids, &pid);
187*98021e37SSteven Rostedt 		while (!ret) {
188*98021e37SSteven Rostedt 			ret = trace_pid_list_set(pid_list, pid);
189*98021e37SSteven Rostedt 			if (ret < 0)
190*98021e37SSteven Rostedt 				goto out;
191*98021e37SSteven Rostedt 
192*98021e37SSteven Rostedt 			ret = trace_pid_list_next(filtered_pids, pid + 1, &pid);
193*98021e37SSteven Rostedt 			nr_pids++;
194*98021e37SSteven Rostedt 		}
195*98021e37SSteven Rostedt 	}
196*98021e37SSteven Rostedt 
197*98021e37SSteven Rostedt 	ret = 0;
198*98021e37SSteven Rostedt 	while (cnt > 0) {
199*98021e37SSteven Rostedt 
200*98021e37SSteven Rostedt 		pos = 0;
201*98021e37SSteven Rostedt 
202*98021e37SSteven Rostedt 		ret = trace_get_user(&parser, ubuf, cnt, &pos);
203*98021e37SSteven Rostedt 		if (ret < 0)
204*98021e37SSteven Rostedt 			break;
205*98021e37SSteven Rostedt 
206*98021e37SSteven Rostedt 		read += ret;
207*98021e37SSteven Rostedt 		ubuf += ret;
208*98021e37SSteven Rostedt 		cnt -= ret;
209*98021e37SSteven Rostedt 
210*98021e37SSteven Rostedt 		if (!trace_parser_loaded(&parser))
211*98021e37SSteven Rostedt 			break;
212*98021e37SSteven Rostedt 
213*98021e37SSteven Rostedt 		ret = -EINVAL;
214*98021e37SSteven Rostedt 		if (kstrtoul(parser.buffer, 0, &val))
215*98021e37SSteven Rostedt 			break;
216*98021e37SSteven Rostedt 
217*98021e37SSteven Rostedt 		pid = (pid_t)val;
218*98021e37SSteven Rostedt 
219*98021e37SSteven Rostedt 		if (trace_pid_list_set(pid_list, pid) < 0) {
220*98021e37SSteven Rostedt 			ret = -1;
221*98021e37SSteven Rostedt 			break;
222*98021e37SSteven Rostedt 		}
223*98021e37SSteven Rostedt 		nr_pids++;
224*98021e37SSteven Rostedt 
225*98021e37SSteven Rostedt 		trace_parser_clear(&parser);
226*98021e37SSteven Rostedt 		ret = 0;
227*98021e37SSteven Rostedt 	}
228*98021e37SSteven Rostedt  out:
229*98021e37SSteven Rostedt 	trace_parser_put(&parser);
230*98021e37SSteven Rostedt 
231*98021e37SSteven Rostedt 	if (ret < 0) {
232*98021e37SSteven Rostedt 		trace_pid_list_free(pid_list);
233*98021e37SSteven Rostedt 		return ret;
234*98021e37SSteven Rostedt 	}
235*98021e37SSteven Rostedt 
236*98021e37SSteven Rostedt 	if (!nr_pids) {
237*98021e37SSteven Rostedt 		/* Cleared the list of pids */
238*98021e37SSteven Rostedt 		trace_pid_list_free(pid_list);
239*98021e37SSteven Rostedt 		pid_list = NULL;
240*98021e37SSteven Rostedt 	}
241*98021e37SSteven Rostedt 
242*98021e37SSteven Rostedt 	*new_pid_list = pid_list;
243*98021e37SSteven Rostedt 
244*98021e37SSteven Rostedt 	return read;
245*98021e37SSteven Rostedt }
246*98021e37SSteven Rostedt 
247