1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * mm/lowmem_dbg.c
4 *
5 * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd.
6 */
7 #define pr_fmt(fmt) "lowmem:" fmt
8
9 #include <linux/mm.h>
10 #include <linux/oom.h>
11 #include <linux/rcupdate.h>
12 #include <linux/mutex.h>
13 #include <linux/jiffies.h>
14 #include <linux/workqueue.h>
15 #include <linux/freezer.h>
16 #include <linux/lowmem_dbg.h>
17
18 #define LMK_PRT_TSK_RSS 0
19 #define LMK_INTERVAL 15
20
21 /* SERVICE_ADJ(5) * OOM_SCORE_ADJ_MAX / -OOM_DISABLE */
22 #define LMK_SERVICE_ADJ 1000
23 /* defiine TASK STATE String */
24 #define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPNn"
25
26 static unsigned long long last_jiffs;
27 static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
28 static void lowmem_dump(struct work_struct *work);
29
30 static DEFINE_MUTEX(lowmem_dump_mutex);
31 static DECLARE_WORK(lowmem_dbg_verbose_wk, lowmem_dump);
32
task_state_char(unsigned long state)33 static int task_state_char(unsigned long state)
34 {
35 int bit = state ? __ffs(state) + 1 : 0;
36
37 return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
38 }
39
tasks_dump(bool verbose)40 static void tasks_dump(bool verbose)
41 {
42 struct task_struct *p = NULL;
43 struct task_struct *task = NULL;
44 short tsk_oom_adj = 0;
45 unsigned long tsk_nr_ptes = 0;
46 char frozen_mark = ' ';
47
48 pr_info("[ pid ] uid tgid total_vm rss nptes swap adj s name\n");
49
50 rcu_read_lock();
51 for_each_process(p) {
52 task = find_lock_task_mm(p);
53 if (!task) {
54 /*
55 * This is a kthread or all of p's threads have already
56 * detached their mm's. There's no need to report
57 * them; they can't be oom killed anyway.
58 */
59 continue;
60 }
61
62 tsk_oom_adj = task->signal->oom_score_adj;
63 if (!verbose && tsk_oom_adj &&
64 (tsk_oom_adj <= LMK_SERVICE_ADJ) &&
65 (get_mm_rss(task->mm) < LMK_PRT_TSK_RSS)) {
66 task_unlock(task);
67 continue;
68 }
69
70 tsk_nr_ptes = mm_pgtables_bytes(task->mm);
71
72 frozen_mark = frozen(task) ? '*' : ' ';
73
74 pr_info("[%5d] %5d %5d %8lu %6lu %5lu %5lu %5hd %c %s%c\n",
75 task->pid, from_kuid(&init_user_ns, task_uid(task)),
76 task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
77 tsk_nr_ptes,
78 get_mm_counter(task->mm, MM_SWAPENTS),
79 tsk_oom_adj,
80 task_state_char(task->state),
81 task->comm,
82 frozen_mark); /*lint !e1058*/
83 task_unlock(task);
84 }
85 rcu_read_unlock();
86 }
87
lowmem_dump(struct work_struct *work)88 static void lowmem_dump(struct work_struct *work)
89 {
90 bool verbose = (work == &lowmem_dbg_verbose_wk) ? true : false;
91
92 mutex_lock(&lowmem_dump_mutex);
93 #if defined(SHOW_MEM_FILTER_PAGE_COUNT)
94 show_mem(SHOW_MEM_FILTER_NODES |
95 (verbose ? 0 : SHOW_MEM_FILTER_PAGE_COUNT), NULL);
96 #else
97 show_mem(SHOW_MEM_FILTER_NODES, NULL);
98 #endif
99 tasks_dump(verbose);
100 mutex_unlock(&lowmem_dump_mutex);
101 }
102
lowmem_dbg(short oom_score_adj)103 void lowmem_dbg(short oom_score_adj)
104 {
105 unsigned long long jiffs = get_jiffies_64();
106
107 if (oom_score_adj == 0) {
108 schedule_work(&lowmem_dbg_verbose_wk);
109 } else if (time_after64(jiffs, (last_jiffs + LMK_INTERVAL * HZ))) {
110 last_jiffs = get_jiffies_64();
111 schedule_work(&lowmem_dbg_verbose_wk);
112 }
113 }
114
115