xref: /openbmc/linux/kernel/trace/pid_list.c (revision 6954e415)
1*6954e415SSteven Rostedt (VMware) // SPDX-License-Identifier: GPL-2.0
2*6954e415SSteven Rostedt (VMware) /*
3*6954e415SSteven Rostedt (VMware)  * Copyright (C) 2021 VMware Inc, Steven Rostedt <rostedt@goodmis.org>
4*6954e415SSteven Rostedt (VMware)  */
5*6954e415SSteven Rostedt (VMware) #include <linux/vmalloc.h>
6*6954e415SSteven Rostedt (VMware) #include <linux/slab.h>
7*6954e415SSteven Rostedt (VMware) #include "trace.h"
8*6954e415SSteven Rostedt (VMware) 
9*6954e415SSteven Rostedt (VMware) /**
10*6954e415SSteven Rostedt (VMware)  * trace_pid_list_is_set - test if the pid is set in the list
11*6954e415SSteven Rostedt (VMware)  * @pid_list: The pid list to test
12*6954e415SSteven Rostedt (VMware)  * @pid: The pid to to see if set in the list.
13*6954e415SSteven Rostedt (VMware)  *
14*6954e415SSteven Rostedt (VMware)  * Tests if @pid is is set in the @pid_list. This is usually called
15*6954e415SSteven Rostedt (VMware)  * from the scheduler when a task is scheduled. Its pid is checked
16*6954e415SSteven Rostedt (VMware)  * if it should be traced or not.
17*6954e415SSteven Rostedt (VMware)  *
18*6954e415SSteven Rostedt (VMware)  * Return true if the pid is in the list, false otherwise.
19*6954e415SSteven Rostedt (VMware)  */
20*6954e415SSteven Rostedt (VMware) bool trace_pid_list_is_set(struct trace_pid_list *pid_list, unsigned int pid)
21*6954e415SSteven Rostedt (VMware) {
22*6954e415SSteven Rostedt (VMware) 	/*
23*6954e415SSteven Rostedt (VMware) 	 * If pid_max changed after filtered_pids was created, we
24*6954e415SSteven Rostedt (VMware) 	 * by default ignore all pids greater than the previous pid_max.
25*6954e415SSteven Rostedt (VMware) 	 */
26*6954e415SSteven Rostedt (VMware) 	if (pid >= pid_list->pid_max)
27*6954e415SSteven Rostedt (VMware) 		return false;
28*6954e415SSteven Rostedt (VMware) 
29*6954e415SSteven Rostedt (VMware) 	return test_bit(pid, pid_list->pids);
30*6954e415SSteven Rostedt (VMware) }
31*6954e415SSteven Rostedt (VMware) 
32*6954e415SSteven Rostedt (VMware) /**
33*6954e415SSteven Rostedt (VMware)  * trace_pid_list_set - add a pid to the list
34*6954e415SSteven Rostedt (VMware)  * @pid_list: The pid list to add the @pid to.
35*6954e415SSteven Rostedt (VMware)  * @pid: The pid to add.
36*6954e415SSteven Rostedt (VMware)  *
37*6954e415SSteven Rostedt (VMware)  * Adds @pid to @pid_list. This is usually done explicitly by a user
38*6954e415SSteven Rostedt (VMware)  * adding a task to be traced, or indirectly by the fork function
39*6954e415SSteven Rostedt (VMware)  * when children should be traced and a task's pid is in the list.
40*6954e415SSteven Rostedt (VMware)  *
41*6954e415SSteven Rostedt (VMware)  * Return 0 on success, negative otherwise.
42*6954e415SSteven Rostedt (VMware)  */
43*6954e415SSteven Rostedt (VMware) int trace_pid_list_set(struct trace_pid_list *pid_list, unsigned int pid)
44*6954e415SSteven Rostedt (VMware) {
45*6954e415SSteven Rostedt (VMware) 	/* Sorry, but we don't support pid_max changing after setting */
46*6954e415SSteven Rostedt (VMware) 	if (pid >= pid_list->pid_max)
47*6954e415SSteven Rostedt (VMware) 		return -EINVAL;
48*6954e415SSteven Rostedt (VMware) 
49*6954e415SSteven Rostedt (VMware) 	set_bit(pid, pid_list->pids);
50*6954e415SSteven Rostedt (VMware) 
51*6954e415SSteven Rostedt (VMware) 	return 0;
52*6954e415SSteven Rostedt (VMware) }
53*6954e415SSteven Rostedt (VMware) 
54*6954e415SSteven Rostedt (VMware) /**
55*6954e415SSteven Rostedt (VMware)  * trace_pid_list_clear - remove a pid from the list
56*6954e415SSteven Rostedt (VMware)  * @pid_list: The pid list to remove the @pid from.
57*6954e415SSteven Rostedt (VMware)  * @pid: The pid to remove.
58*6954e415SSteven Rostedt (VMware)  *
59*6954e415SSteven Rostedt (VMware)  * Removes @pid from @pid_list. This is usually done explicitly by a user
60*6954e415SSteven Rostedt (VMware)  * removing tasks from tracing, or indirectly by the exit function
61*6954e415SSteven Rostedt (VMware)  * when a task that is set to be traced exits.
62*6954e415SSteven Rostedt (VMware)  *
63*6954e415SSteven Rostedt (VMware)  * Return 0 on success, negative otherwise.
64*6954e415SSteven Rostedt (VMware)  */
65*6954e415SSteven Rostedt (VMware) int trace_pid_list_clear(struct trace_pid_list *pid_list, unsigned int pid)
66*6954e415SSteven Rostedt (VMware) {
67*6954e415SSteven Rostedt (VMware) 	/* Sorry, but we don't support pid_max changing after setting */
68*6954e415SSteven Rostedt (VMware) 	if (pid >= pid_list->pid_max)
69*6954e415SSteven Rostedt (VMware) 		return -EINVAL;
70*6954e415SSteven Rostedt (VMware) 
71*6954e415SSteven Rostedt (VMware) 	clear_bit(pid, pid_list->pids);
72*6954e415SSteven Rostedt (VMware) 
73*6954e415SSteven Rostedt (VMware) 	return 0;
74*6954e415SSteven Rostedt (VMware) }
75*6954e415SSteven Rostedt (VMware) 
76*6954e415SSteven Rostedt (VMware) /**
77*6954e415SSteven Rostedt (VMware)  * trace_pid_list_next - return the next pid in the list
78*6954e415SSteven Rostedt (VMware)  * @pid_list: The pid list to examine.
79*6954e415SSteven Rostedt (VMware)  * @pid: The pid to start from
80*6954e415SSteven Rostedt (VMware)  * @next: The pointer to place the pid that is set starting from @pid.
81*6954e415SSteven Rostedt (VMware)  *
82*6954e415SSteven Rostedt (VMware)  * Looks for the next consecutive pid that is in @pid_list starting
83*6954e415SSteven Rostedt (VMware)  * at the pid specified by @pid. If one is set (including @pid), then
84*6954e415SSteven Rostedt (VMware)  * that pid is placed into @next.
85*6954e415SSteven Rostedt (VMware)  *
86*6954e415SSteven Rostedt (VMware)  * Return 0 when a pid is found, -1 if there are no more pids included.
87*6954e415SSteven Rostedt (VMware)  */
88*6954e415SSteven Rostedt (VMware) int trace_pid_list_next(struct trace_pid_list *pid_list, unsigned int pid,
89*6954e415SSteven Rostedt (VMware) 			unsigned int *next)
90*6954e415SSteven Rostedt (VMware) {
91*6954e415SSteven Rostedt (VMware) 	pid = find_next_bit(pid_list->pids, pid_list->pid_max, pid);
92*6954e415SSteven Rostedt (VMware) 
93*6954e415SSteven Rostedt (VMware) 	if (pid < pid_list->pid_max) {
94*6954e415SSteven Rostedt (VMware) 		*next = pid;
95*6954e415SSteven Rostedt (VMware) 		return 0;
96*6954e415SSteven Rostedt (VMware) 	}
97*6954e415SSteven Rostedt (VMware) 	return -1;
98*6954e415SSteven Rostedt (VMware) }
99*6954e415SSteven Rostedt (VMware) 
100*6954e415SSteven Rostedt (VMware) /**
101*6954e415SSteven Rostedt (VMware)  * trace_pid_list_first - return the first pid in the list
102*6954e415SSteven Rostedt (VMware)  * @pid_list: The pid list to examine.
103*6954e415SSteven Rostedt (VMware)  * @pid: The pointer to place the pid first found pid that is set.
104*6954e415SSteven Rostedt (VMware)  *
105*6954e415SSteven Rostedt (VMware)  * Looks for the first pid that is set in @pid_list, and places it
106*6954e415SSteven Rostedt (VMware)  * into @pid if found.
107*6954e415SSteven Rostedt (VMware)  *
108*6954e415SSteven Rostedt (VMware)  * Return 0 when a pid is found, -1 if there are no pids set.
109*6954e415SSteven Rostedt (VMware)  */
110*6954e415SSteven Rostedt (VMware) int trace_pid_list_first(struct trace_pid_list *pid_list, unsigned int *pid)
111*6954e415SSteven Rostedt (VMware) {
112*6954e415SSteven Rostedt (VMware) 	unsigned int first;
113*6954e415SSteven Rostedt (VMware) 
114*6954e415SSteven Rostedt (VMware) 	first = find_first_bit(pid_list->pids, pid_list->pid_max);
115*6954e415SSteven Rostedt (VMware) 
116*6954e415SSteven Rostedt (VMware) 	if (first < pid_list->pid_max) {
117*6954e415SSteven Rostedt (VMware) 		*pid = first;
118*6954e415SSteven Rostedt (VMware) 		return 0;
119*6954e415SSteven Rostedt (VMware) 	}
120*6954e415SSteven Rostedt (VMware) 	return -1;
121*6954e415SSteven Rostedt (VMware) }
122*6954e415SSteven Rostedt (VMware) 
123*6954e415SSteven Rostedt (VMware) /**
124*6954e415SSteven Rostedt (VMware)  * trace_pid_list_alloc - create a new pid_list
125*6954e415SSteven Rostedt (VMware)  *
126*6954e415SSteven Rostedt (VMware)  * Allocates a new pid_list to store pids into.
127*6954e415SSteven Rostedt (VMware)  *
128*6954e415SSteven Rostedt (VMware)  * Returns the pid_list on success, NULL otherwise.
129*6954e415SSteven Rostedt (VMware)  */
130*6954e415SSteven Rostedt (VMware) struct trace_pid_list *trace_pid_list_alloc(void)
131*6954e415SSteven Rostedt (VMware) {
132*6954e415SSteven Rostedt (VMware) 	struct trace_pid_list *pid_list;
133*6954e415SSteven Rostedt (VMware) 
134*6954e415SSteven Rostedt (VMware) 	pid_list = kmalloc(sizeof(*pid_list), GFP_KERNEL);
135*6954e415SSteven Rostedt (VMware) 	if (!pid_list)
136*6954e415SSteven Rostedt (VMware) 		return NULL;
137*6954e415SSteven Rostedt (VMware) 
138*6954e415SSteven Rostedt (VMware) 	pid_list->pid_max = READ_ONCE(pid_max);
139*6954e415SSteven Rostedt (VMware) 
140*6954e415SSteven Rostedt (VMware) 	pid_list->pids = vzalloc((pid_list->pid_max + 7) >> 3);
141*6954e415SSteven Rostedt (VMware) 	if (!pid_list->pids) {
142*6954e415SSteven Rostedt (VMware) 		kfree(pid_list);
143*6954e415SSteven Rostedt (VMware) 		return NULL;
144*6954e415SSteven Rostedt (VMware) 	}
145*6954e415SSteven Rostedt (VMware) 	return pid_list;
146*6954e415SSteven Rostedt (VMware) }
147*6954e415SSteven Rostedt (VMware) 
148*6954e415SSteven Rostedt (VMware) /**
149*6954e415SSteven Rostedt (VMware)  * trace_pid_list_free - Frees an allocated pid_list.
150*6954e415SSteven Rostedt (VMware)  *
151*6954e415SSteven Rostedt (VMware)  * Frees the memory for a pid_list that was allocated.
152*6954e415SSteven Rostedt (VMware)  */
153*6954e415SSteven Rostedt (VMware) void trace_pid_list_free(struct trace_pid_list *pid_list)
154*6954e415SSteven Rostedt (VMware) {
155*6954e415SSteven Rostedt (VMware) 	if (!pid_list)
156*6954e415SSteven Rostedt (VMware) 		return;
157*6954e415SSteven Rostedt (VMware) 
158*6954e415SSteven Rostedt (VMware) 	vfree(pid_list->pids);
159*6954e415SSteven Rostedt (VMware) 	kfree(pid_list);
160*6954e415SSteven Rostedt (VMware) }
161