18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * mm/rss_threshold.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2022 Huawei Technologies Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
88c2ecf20Sopenharmony_ci#include <linux/mm.h>
98c2ecf20Sopenharmony_ci#include <linux/sched/mm.h>
108c2ecf20Sopenharmony_ci#include "../fs/proc/internal.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ciint proc_pid_rss(struct seq_file *m, struct pid_namespace *ns,
138c2ecf20Sopenharmony_ci				struct pid *pid, struct task_struct *task)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct mm_struct *mm = get_task_mm(task);
168c2ecf20Sopenharmony_ci	unsigned long total_rss;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	if (mm) {
198c2ecf20Sopenharmony_ci		total_rss = get_mm_rss(mm);
208c2ecf20Sopenharmony_ci		seq_printf(m, "VMRss:%lu KB\n", total_rss << (PAGE_SHIFT - 10));
218c2ecf20Sopenharmony_ci		mmput(mm);
228c2ecf20Sopenharmony_ci	}
238c2ecf20Sopenharmony_ci	return 0;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid listen_rss_threshold(struct mm_struct *mm)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	unsigned long total_rss;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	total_rss = get_mm_rss(mm);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (!(mm->owner) || mm->rss_threshold == 0)
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	total_rss = total_rss  << (PAGE_SHIFT - 10);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (likely(total_rss <= mm->rss_threshold))
388c2ecf20Sopenharmony_ci		return;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (mm->owner->comm)
418c2ecf20Sopenharmony_ci		pr_err("rss_threshold monitor:Pid:%d [%s] rss size:%lu KB is out of range:%lu KB\n",
428c2ecf20Sopenharmony_ci				mm->owner->pid, mm->owner->comm,
438c2ecf20Sopenharmony_ci				total_rss,
448c2ecf20Sopenharmony_ci				mm->rss_threshold);
458c2ecf20Sopenharmony_ci	else
468c2ecf20Sopenharmony_ci		pr_err("rss_threshold monitor:Pid:%d [NULL] rss size:%lu KB is out of range:%lu KB\n",
478c2ecf20Sopenharmony_ci				mm->owner->pid,
488c2ecf20Sopenharmony_ci				total_rss,
498c2ecf20Sopenharmony_ci				mm->rss_threshold);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic ssize_t rss_threshold_write(struct file *file, const char __user *buf,
538c2ecf20Sopenharmony_ci					size_t count, loff_t *ppos)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
568c2ecf20Sopenharmony_ci	struct task_struct *p;
578c2ecf20Sopenharmony_ci	struct mm_struct *mm = NULL;
588c2ecf20Sopenharmony_ci	unsigned long mem_total;
598c2ecf20Sopenharmony_ci	unsigned long rss_threshold;
608c2ecf20Sopenharmony_ci	int err;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	err = kstrtoul_from_user(buf, count, 0, &rss_threshold);
638c2ecf20Sopenharmony_ci	if (err < 0)
648c2ecf20Sopenharmony_ci		return err;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	mem_total = totalram_pages() << (PAGE_SHIFT - 10);
678c2ecf20Sopenharmony_ci	if (rss_threshold < 0 || rss_threshold > mem_total)
688c2ecf20Sopenharmony_ci		return -EINVAL;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	p = get_proc_task(inode);
718c2ecf20Sopenharmony_ci	if (!p)
728c2ecf20Sopenharmony_ci		return -ESRCH;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	mm = get_task_mm(p);
758c2ecf20Sopenharmony_ci	if (mm) {
768c2ecf20Sopenharmony_ci		mm->rss_threshold = rss_threshold;
778c2ecf20Sopenharmony_ci		listen_rss_threshold(mm);
788c2ecf20Sopenharmony_ci		mmput(mm);
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	put_task_struct(p);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return count;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int rss_threshold_show(struct seq_file *m, void *v)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct inode *inode = m->private;
898c2ecf20Sopenharmony_ci	struct task_struct *p;
908c2ecf20Sopenharmony_ci	struct mm_struct *mm = NULL;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	p = get_proc_task(inode);
938c2ecf20Sopenharmony_ci	if (!p)
948c2ecf20Sopenharmony_ci		return -ESRCH;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	mm = get_task_mm(p);
978c2ecf20Sopenharmony_ci	if (mm) {
988c2ecf20Sopenharmony_ci		seq_printf(m, "Threshold:%lu KB\n", mm->rss_threshold);
998c2ecf20Sopenharmony_ci		mmput(mm);
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	put_task_struct(p);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int rss_threshold_open(struct inode *inode, struct file *filp)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	return single_open(filp, rss_threshold_show, inode);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ciconst struct file_operations proc_pid_rss_threshold_operations = {
1128c2ecf20Sopenharmony_ci	.open		= rss_threshold_open,
1138c2ecf20Sopenharmony_ci	.read		= seq_read,
1148c2ecf20Sopenharmony_ci	.write		= rss_threshold_write,
1158c2ecf20Sopenharmony_ci	.llseek		= seq_lseek,
1168c2ecf20Sopenharmony_ci	.release	= single_release,
1178c2ecf20Sopenharmony_ci};
118