Commit e851dfae authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'kgdb-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux

Pull kgdb update from Daniel Thompson:
 "A single patch this cycle.

  We replace some open-coded routines to classify task states with the
  scheduler's own function to do this. Alongside the obvious benefits of
  removing funky code and aligning more exactly with the scheduler's
  task classification, this also fixes a long standing compiler warning
  by removing the open-coded routines that generated the warning"

* tag 'kgdb-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux:
  kdb: Adopt scheduler's task classification
parents a2b03e48 b77dbc86
...@@ -46,7 +46,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr) ...@@ -46,7 +46,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr)
* btp <pid> Kernel stack for <pid> * btp <pid> Kernel stack for <pid>
* btt <address-expression> Kernel stack for task structure at * btt <address-expression> Kernel stack for task structure at
* <address-expression> * <address-expression>
* bta [DRSTCZEUIMA] All useful processes, optionally * bta [state_chars>|A] All useful processes, optionally
* filtered by state * filtered by state
* btc [<cpu>] The current process on one cpu, * btc [<cpu>] The current process on one cpu,
* default is all cpus * default is all cpus
...@@ -74,7 +74,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr) ...@@ -74,7 +74,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr)
*/ */
static int static int
kdb_bt1(struct task_struct *p, unsigned long mask, bool btaprompt) kdb_bt1(struct task_struct *p, const char *mask, bool btaprompt)
{ {
char ch; char ch;
...@@ -120,7 +120,7 @@ kdb_bt_cpu(unsigned long cpu) ...@@ -120,7 +120,7 @@ kdb_bt_cpu(unsigned long cpu)
return; return;
} }
kdb_bt1(kdb_tsk, ~0UL, false); kdb_bt1(kdb_tsk, "A", false);
} }
int int
...@@ -138,8 +138,8 @@ kdb_bt(int argc, const char **argv) ...@@ -138,8 +138,8 @@ kdb_bt(int argc, const char **argv)
if (strcmp(argv[0], "bta") == 0) { if (strcmp(argv[0], "bta") == 0) {
struct task_struct *g, *p; struct task_struct *g, *p;
unsigned long cpu; unsigned long cpu;
unsigned long mask = kdb_task_state_string(argc ? argv[1] : const char *mask = argc ? argv[1] : kdbgetenv("PS");
NULL);
if (argc == 0) if (argc == 0)
kdb_ps_suppressed(); kdb_ps_suppressed();
/* Run the active tasks first */ /* Run the active tasks first */
...@@ -167,7 +167,7 @@ kdb_bt(int argc, const char **argv) ...@@ -167,7 +167,7 @@ kdb_bt(int argc, const char **argv)
return diag; return diag;
p = find_task_by_pid_ns(pid, &init_pid_ns); p = find_task_by_pid_ns(pid, &init_pid_ns);
if (p) if (p)
return kdb_bt1(p, ~0UL, false); return kdb_bt1(p, "A", false);
kdb_printf("No process with pid == %ld found\n", pid); kdb_printf("No process with pid == %ld found\n", pid);
return 0; return 0;
} else if (strcmp(argv[0], "btt") == 0) { } else if (strcmp(argv[0], "btt") == 0) {
...@@ -176,7 +176,7 @@ kdb_bt(int argc, const char **argv) ...@@ -176,7 +176,7 @@ kdb_bt(int argc, const char **argv)
diag = kdbgetularg((char *)argv[1], &addr); diag = kdbgetularg((char *)argv[1], &addr);
if (diag) if (diag)
return diag; return diag;
return kdb_bt1((struct task_struct *)addr, ~0UL, false); return kdb_bt1((struct task_struct *)addr, "A", false);
} else if (strcmp(argv[0], "btc") == 0) { } else if (strcmp(argv[0], "btc") == 0) {
unsigned long cpu = ~0; unsigned long cpu = ~0;
if (argc > 1) if (argc > 1)
...@@ -212,7 +212,7 @@ kdb_bt(int argc, const char **argv) ...@@ -212,7 +212,7 @@ kdb_bt(int argc, const char **argv)
kdb_show_stack(kdb_current_task, (void *)addr); kdb_show_stack(kdb_current_task, (void *)addr);
return 0; return 0;
} else { } else {
return kdb_bt1(kdb_current_task, ~0UL, false); return kdb_bt1(kdb_current_task, "A", false);
} }
} }
......
...@@ -2203,8 +2203,8 @@ static void kdb_cpu_status(void) ...@@ -2203,8 +2203,8 @@ static void kdb_cpu_status(void)
state = 'D'; /* cpu is online but unresponsive */ state = 'D'; /* cpu is online but unresponsive */
} else { } else {
state = ' '; /* cpu is responding to kdb */ state = ' '; /* cpu is responding to kdb */
if (kdb_task_state_char(KDB_TSK(i)) == 'I') if (kdb_task_state_char(KDB_TSK(i)) == '-')
state = 'I'; /* idle task */ state = '-'; /* idle task */
} }
if (state != prev_state) { if (state != prev_state) {
if (prev_state != '?') { if (prev_state != '?') {
...@@ -2271,37 +2271,30 @@ static int kdb_cpu(int argc, const char **argv) ...@@ -2271,37 +2271,30 @@ static int kdb_cpu(int argc, const char **argv)
void kdb_ps_suppressed(void) void kdb_ps_suppressed(void)
{ {
int idle = 0, daemon = 0; int idle = 0, daemon = 0;
unsigned long mask_I = kdb_task_state_string("I"),
mask_M = kdb_task_state_string("M");
unsigned long cpu; unsigned long cpu;
const struct task_struct *p, *g; const struct task_struct *p, *g;
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
p = kdb_curr_task(cpu); p = kdb_curr_task(cpu);
if (kdb_task_state(p, mask_I)) if (kdb_task_state(p, "-"))
++idle; ++idle;
} }
for_each_process_thread(g, p) { for_each_process_thread(g, p) {
if (kdb_task_state(p, mask_M)) if (kdb_task_state(p, "ims"))
++daemon; ++daemon;
} }
if (idle || daemon) { if (idle || daemon) {
if (idle) if (idle)
kdb_printf("%d idle process%s (state I)%s\n", kdb_printf("%d idle process%s (state -)%s\n",
idle, idle == 1 ? "" : "es", idle, idle == 1 ? "" : "es",
daemon ? " and " : ""); daemon ? " and " : "");
if (daemon) if (daemon)
kdb_printf("%d sleeping system daemon (state M) " kdb_printf("%d sleeping system daemon (state [ims]) "
"process%s", daemon, "process%s", daemon,
daemon == 1 ? "" : "es"); daemon == 1 ? "" : "es");
kdb_printf(" suppressed,\nuse 'ps A' to see all.\n"); kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
} }
} }
/*
* kdb_ps - This function implements the 'ps' command which shows a
* list of the active processes.
* ps [DRSTCZEUIMA] All processes, optionally filtered by state
*/
void kdb_ps1(const struct task_struct *p) void kdb_ps1(const struct task_struct *p)
{ {
int cpu; int cpu;
...@@ -2330,17 +2323,25 @@ void kdb_ps1(const struct task_struct *p) ...@@ -2330,17 +2323,25 @@ void kdb_ps1(const struct task_struct *p)
} }
} }
/*
* kdb_ps - This function implements the 'ps' command which shows a
* list of the active processes.
*
* ps [<state_chars>] Show processes, optionally selecting only those whose
* state character is found in <state_chars>.
*/
static int kdb_ps(int argc, const char **argv) static int kdb_ps(int argc, const char **argv)
{ {
struct task_struct *g, *p; struct task_struct *g, *p;
unsigned long mask, cpu; const char *mask;
unsigned long cpu;
if (argc == 0) if (argc == 0)
kdb_ps_suppressed(); kdb_ps_suppressed();
kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n", kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n",
(int)(2*sizeof(void *))+2, "Task Addr", (int)(2*sizeof(void *))+2, "Task Addr",
(int)(2*sizeof(void *))+2, "Thread"); (int)(2*sizeof(void *))+2, "Thread");
mask = kdb_task_state_string(argc ? argv[1] : NULL); mask = argc ? argv[1] : kdbgetenv("PS");
/* Run the active tasks first */ /* Run the active tasks first */
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
if (KDB_FLAG(CMD_INTERRUPT)) if (KDB_FLAG(CMD_INTERRUPT))
...@@ -2742,8 +2743,8 @@ static kdbtab_t maintab[] = { ...@@ -2742,8 +2743,8 @@ static kdbtab_t maintab[] = {
}, },
{ .name = "bta", { .name = "bta",
.func = kdb_bt, .func = kdb_bt,
.usage = "[D|R|S|T|C|Z|E|U|I|M|A]", .usage = "[<state_chars>|A]",
.help = "Backtrace all processes matching state flag", .help = "Backtrace all processes whose state matches",
.flags = KDB_ENABLE_INSPECT, .flags = KDB_ENABLE_INSPECT,
}, },
{ .name = "btc", { .name = "btc",
...@@ -2797,7 +2798,7 @@ static kdbtab_t maintab[] = { ...@@ -2797,7 +2798,7 @@ static kdbtab_t maintab[] = {
}, },
{ .name = "ps", { .name = "ps",
.func = kdb_ps, .func = kdb_ps,
.usage = "[<flags>|A]", .usage = "[<state_chars>|A]",
.help = "Display active task list", .help = "Display active task list",
.flags = KDB_ENABLE_INSPECT, .flags = KDB_ENABLE_INSPECT,
}, },
......
...@@ -190,10 +190,8 @@ extern char kdb_grep_string[]; ...@@ -190,10 +190,8 @@ extern char kdb_grep_string[];
extern int kdb_grep_leading; extern int kdb_grep_leading;
extern int kdb_grep_trailing; extern int kdb_grep_trailing;
extern char *kdb_cmds[]; extern char *kdb_cmds[];
extern unsigned long kdb_task_state_string(const char *);
extern char kdb_task_state_char (const struct task_struct *); extern char kdb_task_state_char (const struct task_struct *);
extern unsigned long kdb_task_state(const struct task_struct *p, extern bool kdb_task_state(const struct task_struct *p, const char *mask);
unsigned long mask);
extern void kdb_ps_suppressed(void); extern void kdb_ps_suppressed(void);
extern void kdb_ps1(const struct task_struct *p); extern void kdb_ps1(const struct task_struct *p);
extern void kdb_send_sig(struct task_struct *p, int sig); extern void kdb_send_sig(struct task_struct *p, int sig);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kdb.h> #include <linux/kdb.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ctype.h>
#include "kdb_private.h" #include "kdb_private.h"
/* /*
...@@ -473,82 +474,7 @@ int kdb_putword(unsigned long addr, unsigned long word, size_t size) ...@@ -473,82 +474,7 @@ int kdb_putword(unsigned long addr, unsigned long word, size_t size)
return diag; return diag;
} }
/*
* kdb_task_state_string - Convert a string containing any of the
* letters DRSTCZEUIMA to a mask for the process state field and
* return the value. If no argument is supplied, return the mask
* that corresponds to environment variable PS, DRSTCZEU by
* default.
* Inputs:
* s String to convert
* Returns:
* Mask for process state.
* Notes:
* The mask folds data from several sources into a single long value, so
* be careful not to overlap the bits. TASK_* bits are in the LSB,
* special cases like UNRUNNABLE are in the MSB. As of 2.6.10-rc1 there
* is no overlap between TASK_* and EXIT_* but that may not always be
* true, so EXIT_* bits are shifted left 16 bits before being stored in
* the mask.
*/
/* unrunnable is < 0 */
#define UNRUNNABLE (1UL << (8*sizeof(unsigned long) - 1))
#define RUNNING (1UL << (8*sizeof(unsigned long) - 2))
#define IDLE (1UL << (8*sizeof(unsigned long) - 3))
#define DAEMON (1UL << (8*sizeof(unsigned long) - 4))
unsigned long kdb_task_state_string(const char *s)
{
long res = 0;
if (!s) {
s = kdbgetenv("PS");
if (!s)
s = "DRSTCZEU"; /* default value for ps */
}
while (*s) {
switch (*s) {
case 'D':
res |= TASK_UNINTERRUPTIBLE;
break;
case 'R':
res |= RUNNING;
break;
case 'S':
res |= TASK_INTERRUPTIBLE;
break;
case 'T':
res |= TASK_STOPPED;
break;
case 'C':
res |= TASK_TRACED;
break;
case 'Z':
res |= EXIT_ZOMBIE << 16;
break;
case 'E':
res |= EXIT_DEAD << 16;
break;
case 'U':
res |= UNRUNNABLE;
break;
case 'I':
res |= IDLE;
break;
case 'M':
res |= DAEMON;
break;
case 'A':
res = ~0UL;
break;
default:
kdb_func_printf("unknown flag '%c' ignored\n", *s);
break;
}
++s;
}
return res;
}
/* /*
* kdb_task_state_char - Return the character that represents the task state. * kdb_task_state_char - Return the character that represents the task state.
...@@ -559,7 +485,6 @@ unsigned long kdb_task_state_string(const char *s) ...@@ -559,7 +485,6 @@ unsigned long kdb_task_state_string(const char *s)
*/ */
char kdb_task_state_char (const struct task_struct *p) char kdb_task_state_char (const struct task_struct *p)
{ {
unsigned int p_state;
unsigned long tmp; unsigned long tmp;
char state; char state;
int cpu; int cpu;
...@@ -568,25 +493,18 @@ char kdb_task_state_char (const struct task_struct *p) ...@@ -568,25 +493,18 @@ char kdb_task_state_char (const struct task_struct *p)
copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsigned long))) copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsigned long)))
return 'E'; return 'E';
cpu = kdb_process_cpu(p); state = task_state_to_char((struct task_struct *) p);
p_state = READ_ONCE(p->__state);
state = (p_state == 0) ? 'R' :
(p_state < 0) ? 'U' :
(p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
(p_state & TASK_STOPPED) ? 'T' :
(p_state & TASK_TRACED) ? 'C' :
(p->exit_state & EXIT_ZOMBIE) ? 'Z' :
(p->exit_state & EXIT_DEAD) ? 'E' :
(p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
if (is_idle_task(p)) { if (is_idle_task(p)) {
/* Idle task. Is it really idle, apart from the kdb /* Idle task. Is it really idle, apart from the kdb
* interrupt? */ * interrupt? */
cpu = kdb_process_cpu(p);
if (!kdb_task_has_cpu(p) || kgdb_info[cpu].irq_depth == 1) { if (!kdb_task_has_cpu(p) || kgdb_info[cpu].irq_depth == 1) {
if (cpu != kdb_initial_cpu) if (cpu != kdb_initial_cpu)
state = 'I'; /* idle task */ state = '-'; /* idle task */
} }
} else if (!p->mm && state == 'S') { } else if (!p->mm && strchr("IMS", state)) {
state = 'M'; /* sleeping system daemon */ state = tolower(state); /* sleeping system daemon */
} }
return state; return state;
} }
...@@ -596,14 +514,28 @@ char kdb_task_state_char (const struct task_struct *p) ...@@ -596,14 +514,28 @@ char kdb_task_state_char (const struct task_struct *p)
* given by the mask. * given by the mask.
* Inputs: * Inputs:
* p struct task for the process * p struct task for the process
* mask mask from kdb_task_state_string to select processes * mask set of characters used to select processes; both NULL
* and the empty string mean adopt a default filter, which
* is to suppress sleeping system daemons and the idle tasks
* Returns: * Returns:
* True if the process matches at least one criteria defined by the mask. * True if the process matches at least one criteria defined by the mask.
*/ */
unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask) bool kdb_task_state(const struct task_struct *p, const char *mask)
{ {
char state[] = { kdb_task_state_char(p), '\0' }; char state = kdb_task_state_char(p);
return (mask & kdb_task_state_string(state)) != 0;
/* If there is no mask, then we will filter code that runs when the
* scheduler is idling and any system daemons that are currently
* sleeping.
*/
if (!mask || mask[0] == '\0')
return !strchr("-ims", state);
/* A is a special case that matches all states */
if (strchr(mask, 'A'))
return true;
return strchr(mask, state);
} }
/* Maintain a small stack of kdb_flags to allow recursion without disturbing /* Maintain a small stack of kdb_flags to allow recursion without disturbing
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment