Skip to content

Commit

Permalink
tracing: Map all PIDs to command lines
Browse files Browse the repository at this point in the history
The default max PID is set by PID_MAX_DEFAULT, and the tracing
infrastructure uses this number to map PIDs to the comm names of the
tasks, such output of the trace can show names from the recorded PIDs in
the ring buffer. This mapping is also exported to user space via the
"saved_cmdlines" file in the tracefs directory.

But currently the mapping expects the PIDs to be less than
PID_MAX_DEFAULT, which is the default maximum and not the real maximum.
Recently, systemd will increases the maximum value of a PID on the system,
and when tasks are traced that have a PID higher than PID_MAX_DEFAULT, its
comm is not recorded. This leads to the entire trace to have "<...>" as
the comm name, which is pretty useless.

Instead, keep the array mapping the size of PID_MAX_DEFAULT, but instead
of just mapping the index to the comm, map a mask of the PID
(PID_MAX_DEFAULT - 1) to the comm, and find the full PID from the
map_cmdline_to_pid array (that already exists).

This bug goes back to the beginning of ftrace, but hasn't been an issue
until user space started increasing the maximum value of PIDs.

Link: https://lkml.kernel.org/r/[email protected]

Cc: [email protected]
Fixes: bc0c38d ("ftrace: latency tracer infrastructure")
Signed-off-by: Steven Rostedt (VMware) <[email protected]>
  • Loading branch information
rostedt committed Apr 28, 2021
1 parent e1db633 commit 785e3c0
Showing 1 changed file with 15 additions and 26 deletions.
41 changes: 15 additions & 26 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2390,14 +2390,13 @@ static void tracing_stop_tr(struct trace_array *tr)

static int trace_save_cmdline(struct task_struct *tsk)
{
unsigned pid, idx;
unsigned tpid, idx;

/* treat recording of idle task as a success */
if (!tsk->pid)
return 1;

if (unlikely(tsk->pid > PID_MAX_DEFAULT))
return 0;
tpid = tsk->pid & (PID_MAX_DEFAULT - 1);

/*
* It's not the end of the world if we don't get
Expand All @@ -2408,26 +2407,15 @@ static int trace_save_cmdline(struct task_struct *tsk)
if (!arch_spin_trylock(&trace_cmdline_lock))
return 0;

idx = savedcmd->map_pid_to_cmdline[tsk->pid];
idx = savedcmd->map_pid_to_cmdline[tpid];
if (idx == NO_CMDLINE_MAP) {
idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num;

/*
* Check whether the cmdline buffer at idx has a pid
* mapped. We are going to overwrite that entry so we
* need to clear the map_pid_to_cmdline. Otherwise we
* would read the new comm for the old pid.
*/
pid = savedcmd->map_cmdline_to_pid[idx];
if (pid != NO_CMDLINE_MAP)
savedcmd->map_pid_to_cmdline[pid] = NO_CMDLINE_MAP;

savedcmd->map_cmdline_to_pid[idx] = tsk->pid;
savedcmd->map_pid_to_cmdline[tsk->pid] = idx;

savedcmd->map_pid_to_cmdline[tpid] = idx;
savedcmd->cmdline_idx = idx;
}

savedcmd->map_cmdline_to_pid[idx] = tsk->pid;
set_cmdline(idx, tsk->comm);

arch_spin_unlock(&trace_cmdline_lock);
Expand All @@ -2438,6 +2426,7 @@ static int trace_save_cmdline(struct task_struct *tsk)
static void __trace_find_cmdline(int pid, char comm[])
{
unsigned map;
int tpid;

if (!pid) {
strcpy(comm, "<idle>");
Expand All @@ -2449,16 +2438,16 @@ static void __trace_find_cmdline(int pid, char comm[])
return;
}

if (pid > PID_MAX_DEFAULT) {
strcpy(comm, "<...>");
return;
tpid = pid & (PID_MAX_DEFAULT - 1);
map = savedcmd->map_pid_to_cmdline[tpid];
if (map != NO_CMDLINE_MAP) {
tpid = savedcmd->map_cmdline_to_pid[map];
if (tpid == pid) {
strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN);
return;
}
}

map = savedcmd->map_pid_to_cmdline[pid];
if (map != NO_CMDLINE_MAP)
strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN);
else
strcpy(comm, "<...>");
strcpy(comm, "<...>");
}

void trace_find_cmdline(int pid, char comm[])
Expand Down

0 comments on commit 785e3c0

Please sign in to comment.