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