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