Advance to Digital Age
[platform/core/system/stability-monitor-kmod-rpi3.git] / kernel / proc-tsm.c
1 /*
2  * This file is part of stability-monitor-kmod-rpi3
3  *
4  * Copyright © 2019 Samsung Electronics
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see http://www.gnu.org/licenses/
18  */
19
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/init.h>
23 #include <linux/kernel.h>
24
25 #include <linux/fs.h>
26 #include <linux/proc_fs.h>
27 #include <linux/seq_file.h>
28 #include <linux/sched.h>
29 #include <linux/sched/signal.h>
30 #include <linux/sched/cputime.h>
31 #include <linux/mm.h>
32 #include <linux/pid_namespace.h>
33 #include <asm/uaccess.h>
34 #include <linux/time.h>
35 #include <linux/posix-timers.h>
36 #include <linux/kernel_stat.h>
37 #include <linux/fdtable.h>
38 #include <linux/math64.h>
39 #include <linux/task_io_accounting_ops.h>
40 #include <linux/security.h>
41
42 #define DEBUG 0
43 #define PAGE_TO_KB(x) ((x) << (PAGE_SHIFT - 10))
44
45 static struct proc_dir_entry* proc_file;
46 static char *blacklist[10] = {0, };
47 static int blacklist_c = 0;
48
49 module_param_array(blacklist, charp, &blacklist_c, 0000);
50
51 static u64 time_now(void)
52 {
53     return div64_ul(ktime_get_boot_ns(), NSEC_PER_USEC);
54 }
55
56 static inline u64 cputime_to_usecs(const u64 cputime)
57 {
58     // return cputime >> 12;
59     return div64_ul(cputime, NSEC_PER_USEC);
60 }
61
62 static unsigned int count_open_files(struct files_struct *files)
63 {
64     unsigned int open_files = 0;
65     int i;
66     struct fdtable *fdt;
67
68     if (!files)
69         return 0;
70
71     spin_lock(&files->file_lock);
72     fdt = files_fdtable(files);
73
74     /* Find the last non zero cell in open fds array */
75     for (i = fdt->max_fds / BITS_PER_LONG - 1; i >= 0; i--) {
76         if (fdt->open_fds[i])
77             break;
78     }
79
80     /* Count set bits */
81     for (i = (i + 1) * BITS_PER_LONG - 1; i >= 0; i--) {
82         if(test_bit(i, fdt->open_fds))
83             open_files++;
84     }
85
86     spin_unlock(&files->file_lock);
87     return open_files;
88 }
89
90 static int stability_monitor_show(struct seq_file *m, void *v)
91 {
92     struct sysinfo info;
93     struct task_struct *task, *t;
94     struct pid *pid = NULL;
95     pid_t ppid = 0;
96     u64 uptime, utime, stime, ut, st;
97     unsigned long long vm_rss, total_ram;
98     struct task_io_accounting task_ioac;
99     unsigned int open_fds;
100     u32 secid;
101     char *label;
102     u32 label_len;
103     int blacklisted;
104     int i;
105
106     rcu_read_lock();
107
108     /* Uptime in us */
109     uptime = time_now();
110
111     /* Memory info */
112     si_meminfo(&info);
113     total_ram = PAGE_TO_KB(info.totalram);
114
115     seq_put_decimal_ull(m, "", uptime);
116     seq_put_decimal_ull(m, " ", total_ram);
117     seq_printf(m, "\n");
118
119     for_each_process(task) {
120         ppid = task->real_parent->pid;
121         pid = task_pgrp(task);
122         if (!pid)
123             continue;
124
125         task_lock(task);
126
127         if (!task->mm) {
128             task_unlock(task);
129             continue;
130         }
131
132         if (task->flags & (PF_DUMPCORE|PF_SIGNALED|PF_EXITING)) {
133             task_unlock(task);
134             continue;
135         }
136
137         security_cred_getsecid(((struct cred *)task->real_cred), &secid);
138         if (!security_secid_to_secctx(secid, &label, &label_len)) {
139             blacklisted = 0;
140             for (i = 0; i < blacklist_c; i++) {
141                 if (strcmp(label, blacklist[i]) == 0) {
142                     blacklisted = 1;
143                     break;
144                 }
145             }
146             if (blacklisted) {
147                 task_unlock(task);
148                 continue;
149             }
150         }
151
152         /* Memory */
153         vm_rss = get_mm_rss(task->mm);
154
155         /* Open FDs */
156         open_fds = count_open_files(task->files);
157
158         /* CPU time + IO accounting */
159         task_cputime_adjusted(task, &utime, &stime);
160         task_ioac = task->ioac;
161         t = task;
162         while_each_thread(task, t) {
163             task_cputime_adjusted(t, &ut, &st);
164             utime += ut;
165             stime += st;
166             task_io_accounting_add(&task_ioac, &t->ioac);
167         }
168
169         task_unlock(task);
170
171         seq_put_decimal_ll(m, "", task->pid);
172         seq_put_decimal_ll(m, " ", ppid);
173         seq_put_decimal_ull(m, " ", cputime_to_usecs(utime + stime));
174         seq_put_decimal_ull(m, " ", PAGE_TO_KB(vm_rss));
175         seq_put_decimal_ll(m, " ", open_fds);
176         seq_put_decimal_ull(m, " ", task_ioac.read_bytes + task_ioac.write_bytes);
177         seq_printf(m, "\n");
178     }
179
180     rcu_read_unlock();
181
182 #if DEBUG
183     printk(KERN_DEBUG "stability_monitor_show() took %llu us\n", time_now() - uptime);
184 #endif
185
186     return 0;
187 }
188
189 static int stability_monitor_open(struct inode *inode, struct file *file)
190 {
191     return single_open_size(file, stability_monitor_show, NULL, 8192);
192 }
193
194 static const struct file_operations stability_monitor_fops = {
195     .owner      = THIS_MODULE,
196     .open       = stability_monitor_open,
197     .read       = seq_read,
198     .llseek  = seq_lseek,
199     .release = single_release,
200 };
201
202 static int __init stability_monitor_init(void)
203 {
204     proc_file = proc_create("tsm", 0, NULL, &stability_monitor_fops);
205     if (!proc_file)
206         return -ENOMEM;
207
208     return 0;
209 }
210
211 static void __exit stability_monitor_exit(void)
212 {
213     remove_proc_entry("tsm", NULL);
214 }
215
216 module_init(stability_monitor_init);
217 module_exit(stability_monitor_exit);
218
219 MODULE_LICENSE("GPL");