2 * This file is part of stability-monitor-kmod-rpi3
4 * Copyright © 2019 Samsung Electronics
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.
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.
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/
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/init.h>
23 #include <linux/kernel.h>
24 #include <linux/version.h>
27 #include <linux/proc_fs.h>
28 #include <linux/seq_file.h>
29 #include <linux/sched.h>
30 #include <linux/sched/signal.h>
31 #include <linux/sched/cputime.h>
33 #include <linux/pid_namespace.h>
34 #include <asm/uaccess.h>
35 #include <linux/time.h>
36 #include <linux/posix-timers.h>
37 #include <linux/kernel_stat.h>
38 #include <linux/fdtable.h>
39 #include <linux/math64.h>
40 #include <linux/task_io_accounting_ops.h>
41 #include <linux/security.h>
44 #define PAGE_TO_KB(x) ((x) << (PAGE_SHIFT - 10))
46 static struct proc_dir_entry* proc_file;
47 static char *blacklist[10] = {0, };
48 static int blacklist_c = 0;
50 module_param_array(blacklist, charp, &blacklist_c, 0000);
52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
53 /* ktime_get_boot_ns() is renamed to ktime_get_boottime_ns() from v5.3 */
54 static inline u64 ktime_get_boot_ns(void) {
55 return ktime_get_boottime_ns();
57 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) */
59 static u64 time_now(void)
61 return div64_ul(ktime_get_boot_ns(), NSEC_PER_USEC);
64 static inline u64 cputime_to_usecs(const u64 cputime)
66 // return cputime >> 12;
67 return div64_ul(cputime, NSEC_PER_USEC);
70 static unsigned int count_open_files(struct files_struct *files)
72 unsigned int open_files = 0;
79 spin_lock(&files->file_lock);
80 fdt = files_fdtable(files);
82 /* Find the last non zero cell in open fds array */
83 for (i = fdt->max_fds / BITS_PER_LONG - 1; i >= 0; i--) {
89 for (i = (i + 1) * BITS_PER_LONG - 1; i >= 0; i--) {
90 if(test_bit(i, fdt->open_fds))
94 spin_unlock(&files->file_lock);
98 static int stability_monitor_show(struct seq_file *m, void *v)
101 struct task_struct *task, *t;
102 struct pid *pid = NULL;
104 u64 uptime, utime, stime, ut, st;
105 unsigned long long vm_rss, total_ram;
106 struct task_io_accounting task_ioac;
107 unsigned int open_fds;
121 total_ram = PAGE_TO_KB(info.totalram);
123 seq_put_decimal_ull(m, "", uptime);
124 seq_put_decimal_ull(m, " ", total_ram);
127 for_each_process(task) {
128 ppid = task->real_parent->pid;
129 pid = task_pgrp(task);
140 if (task->flags & (PF_DUMPCORE|PF_SIGNALED|PF_EXITING)) {
145 security_cred_getsecid(((struct cred *)task->real_cred), &secid);
146 if (!security_secid_to_secctx(secid, &label, &label_len)) {
148 for (i = 0; i < blacklist_c; i++) {
149 if (strcmp(label, blacklist[i]) == 0) {
161 vm_rss = get_mm_rss(task->mm);
164 open_fds = count_open_files(task->files);
166 /* CPU time + IO accounting */
167 task_cputime_adjusted(task, &utime, &stime);
168 task_ioac = task->ioac;
170 while_each_thread(task, t) {
171 task_cputime_adjusted(t, &ut, &st);
174 task_io_accounting_add(&task_ioac, &t->ioac);
179 seq_put_decimal_ll(m, "", task->pid);
180 seq_put_decimal_ll(m, " ", ppid);
181 seq_put_decimal_ull(m, " ", cputime_to_usecs(utime + stime));
182 seq_put_decimal_ull(m, " ", PAGE_TO_KB(vm_rss));
183 seq_put_decimal_ll(m, " ", open_fds);
184 seq_put_decimal_ull(m, " ", task_ioac.read_bytes + task_ioac.write_bytes);
191 printk(KERN_DEBUG "stability_monitor_show() took %llu us\n", time_now() - uptime);
197 static int stability_monitor_open(struct inode *inode, struct file *file)
199 return single_open_size(file, stability_monitor_show, NULL, 8192);
202 static const struct file_operations stability_monitor_fops = {
203 .owner = THIS_MODULE,
204 .open = stability_monitor_open,
207 .release = single_release,
210 static int __init stability_monitor_init(void)
212 proc_file = proc_create("tsm", 0, NULL, &stability_monitor_fops);
219 static void __exit stability_monitor_exit(void)
221 remove_proc_entry("tsm", NULL);
224 module_init(stability_monitor_init);
225 module_exit(stability_monitor_exit);
227 MODULE_LICENSE("GPL");