diff --git a/fs/proc/base.c b/fs/proc/base.c index 503fce587b67f2c9435bd534fc86f4127d3531e7..27145778c144f26473ca8b8ac9d703b9173abe74 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3361,6 +3361,10 @@ static const struct pid_entry tgid_base_stuff[] = { #endif #ifdef CONFIG_TIME_NS REG("timens_offsets", S_IRUGO|S_IWUSR, proc_timens_offsets_operations), +#endif +#ifdef CONFIG_RSS_THRESHOLD + ONE("rss", S_IRUGO, proc_pid_rss), + REG("rss_threshold", S_IRUGO|S_IWUSR, proc_pid_rss_threshold_operations), #endif REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), #ifdef CONFIG_HAVE_ARCH_TRACEHOOK diff --git a/fs/proc/internal.h b/fs/proc/internal.h index afbe96b6bf77def7e5cd5b3d62e90b20c87728b4..8b91a8395e1dbf0cec529ba80c303e738b9c5522 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -171,6 +171,12 @@ extern int pid_delete_dentry(const struct dentry *); extern int proc_pid_readdir(struct file *, struct dir_context *); struct dentry *proc_pid_lookup(struct dentry *, unsigned int); extern loff_t mem_lseek(struct file *, loff_t, int); +#ifdef CONFIG_RSS_THRESHOLD +extern int proc_pid_rss(struct seq_file *, struct pid_namespace *, + struct pid *, struct task_struct *); +extern void listen_rss_threshold(struct mm_struct *mm); +extern const struct file_operations proc_pid_rss_threshold_operations; +#endif /* Lookups */ typedef struct dentry *instantiate_t(struct dentry *, diff --git a/include/linux/mm.h b/include/linux/mm.h index 01d012727a27a3469cbd10178b9dc08319366bf0..6a92fac06b44fe7b909ea0edcba7e8951ed3d442 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1903,10 +1903,18 @@ static inline unsigned long get_mm_counter(struct mm_struct *mm, int member) void mm_trace_rss_stat(struct mm_struct *mm, int member, long count); +#ifdef CONFIG_RSS_THRESHOLD +void listen_rss_threshold(struct mm_struct *mm); +#endif + static inline void add_mm_counter(struct mm_struct *mm, int member, long value) { long count = atomic_long_add_return(value, &mm->rss_stat.count[member]); +#ifdef CONFIG_RSS_THRESHOLD + listen_rss_threshold(mm); +#endif + mm_trace_rss_stat(mm, member, count); } @@ -1914,6 +1922,10 @@ static inline void inc_mm_counter(struct mm_struct *mm, int member) { long count = atomic_long_inc_return(&mm->rss_stat.count[member]); +#ifdef CONFIG_RSS_THRESHOLD + listen_rss_threshold(mm); +#endif + mm_trace_rss_stat(mm, member, count); } diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index c0aedba56912100e0f8ea86f75973c723e5f5ed2..a9249cb18123ec00fa066f7cb13bc6a292492f41 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -497,6 +497,9 @@ struct mm_struct { unsigned long hiwater_rss; /* High-watermark of RSS usage */ unsigned long hiwater_vm; /* High-water virtual memory usage */ +#ifdef CONFIG_RSS_THRESHOLD + unsigned long rss_threshold; /* A threshold monitor RSS */ +#endif unsigned long total_vm; /* Total pages mapped */ unsigned long locked_vm; /* Pages that have PG_mlocked set */ diff --git a/kernel/fork.c b/kernel/fork.c index 298c44dc5e77f8d298068bf1aa81b4e2e3adabad..0426eb8a40420c5fd7b808dda1b70ea8bf58b88b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1022,6 +1022,9 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, mm->mmap = NULL; mm->mm_rb = RB_ROOT; mm->vmacache_seqnum = 0; +#ifdef CONFIG_RSS_THRESHOLD + mm->rss_threshold = 0; +#endif atomic_set(&mm->mm_users, 1); atomic_set(&mm->mm_count, 1); seqcount_init(&mm->write_protect_seq); diff --git a/mm/Kconfig b/mm/Kconfig index c35f9f8a0857050b4974e7d58b4e3169a4de37ca..291e90d2de323db8914ee77be1f17156a26b6a11 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -948,4 +948,14 @@ config MEMTRACE_ASHMEM help Enable the Ashmem Process Info Show +# +# Use rss_threshold to monitoring RSS +# +config RSS_THRESHOLD + bool "Enable /proc//rss and /proc//rss_threshold to monitoring RSS" + default n + depends on PROC_FS && MEMCG + help + Set a threshold to monitoring RSS in per pid + endmenu diff --git a/mm/Makefile b/mm/Makefile index 4c0ca82c4a64b8a088014094b7da85f62fbbb48f..d193db7a48e05e8154544dc5b642eed2ec85e327 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -66,6 +66,7 @@ ifdef CONFIG_MMU obj-$(CONFIG_ADVISE_SYSCALLS) += madvise.o endif +obj-$(CONFIG_RSS_THRESHOLD) += rss_threshold.o obj-$(CONFIG_MEMTRACE_ASHMEM) += memtrace_ashmem.o obj-$(CONFIG_LMKD_DBG) += lmkd_dbg_trigger.o obj-$(CONFIG_LOWMEM) += lowmem_dbg.o diff --git a/mm/rss_threshold.c b/mm/rss_threshold.c new file mode 100644 index 0000000000000000000000000000000000000000..1fa01abf1401b56bae1201c1ddbb3b40582e0049 --- /dev/null +++ b/mm/rss_threshold.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mm/rss_threshold.c + * + * Copyright (c) 2022 Huawei Technologies Co., Ltd. + */ +#include +#include +#include +#include "../fs/proc/internal.h" + +int proc_pid_rss(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + struct mm_struct *mm = get_task_mm(task); + unsigned long total_rss; + + if (mm) { + total_rss = get_mm_rss(mm); + seq_printf(m, "VMRss:%lu KB\n", total_rss << (PAGE_SHIFT - 10)); + mmput(mm); + } + return 0; +} + +void listen_rss_threshold(struct mm_struct *mm) +{ + unsigned long total_rss; + + total_rss = get_mm_rss(mm); + + if (!(mm->owner) || mm->rss_threshold == 0) + return; + + total_rss = total_rss << (PAGE_SHIFT - 10); + + if (likely(total_rss <= mm->rss_threshold)) + return; + + if (mm->owner->comm) + pr_err("rss_threshold monitor:Pid:%d [%s] rss size:%lu KB is out of range:%lu KB\n", + mm->owner->pid, mm->owner->comm, + total_rss, + mm->rss_threshold); + else + pr_err("rss_threshold monitor:Pid:%d [NULL] rss size:%lu KB is out of range:%lu KB\n", + mm->owner->pid, + total_rss, + mm->rss_threshold); +} + +static ssize_t rss_threshold_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file_inode(file); + struct task_struct *p; + unsigned long mem_total; + unsigned long rss_threshold; + int err; + + err = kstrtoul_from_user(buf, count, 0, &rss_threshold); + if (err < 0) + return err; + + mem_total = totalram_pages() << (PAGE_SHIFT - 10); + if (rss_threshold < 0 || rss_threshold > mem_total) + return -EINVAL; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + if (p->mm) { + p->mm->rss_threshold = rss_threshold; + listen_rss_threshold(p->mm); + } + + put_task_struct(p); + + return count; +} + +static int rss_threshold_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + seq_printf(m, "Threshold:%lu KB\n", p->mm->rss_threshold); + + put_task_struct(p); + + return 0; +} + +static int rss_threshold_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, rss_threshold_show, inode); +} + +const struct file_operations proc_pid_rss_threshold_operations = { + .open = rss_threshold_open, + .read = seq_read, + .write = rss_threshold_write, + .llseek = seq_lseek, + .release = single_release, +};