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
trace_find_filtered_pid(struct trace_pid_list * filtered_pids,pid_t search_pid)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
trace_ignore_this_task(struct trace_pid_list * filtered_pids,struct trace_pid_list * filtered_no_pids,struct task_struct * task)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 */
trace_filter_add_remove_task(struct trace_pid_list * pid_list,struct task_struct * self,struct task_struct * task)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 */
trace_pid_next(struct trace_pid_list * pid_list,void * v,loff_t * pos)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 */
trace_pid_start(struct trace_pid_list * pid_list,loff_t * pos)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 */
trace_pid_show(struct seq_file * m,void * v)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
trace_pid_write(struct trace_pid_list * filtered_pids,struct trace_pid_list ** new_pid_list,const char __user * ubuf,size_t cnt)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