From 3c05af9b5202d128830527e69c1afa97dd84bf0a Mon Sep 17 00:00:00 2001 From: Chen Junlin Date: Tue, 30 Sep 2025 10:29:07 +0800 Subject: [PATCH] anolis: mm: Add a proc interface to display the maximum number of memory mappings the process has ever reached ANBZ: #25523 Problem: When the number of memory mappings required by a process exceeds the limit set by /proc/sys/vm/max_map_count, new mmap() calls will fail and return an error. In such cases, we need to manually increase the value of this parameter. However, it is often difficult to determine what an appropriate value would be. Solution: This patch introduces a new process-specific proc parameter, /proc//max_map_count, which displays the maximum number of memory mappings the process has ever reached. This provides a reference for adjusting the global /proc/sys/vm/max_map_count parameter. Usage: To directly view this parameter for a specific process: cat /proc/1/max_map_count 154 The parameter supports resetting to 0, but writing any other value will result in an error: echo 0 > /proc/1/max_map_count cat /proc/1/max_map_count 0 Signed-off-by: Chen Junlin --- fs/proc/base.c | 69 ++++++++++++++++++++++++++++++++++++++-- include/linux/mm_types.h | 3 ++ kernel/fork.c | 7 ++++ mm/Kconfig | 5 +++ mm/mmap.c | 16 ++++++++++ mm/nommu.c | 8 +++++ 6 files changed, 106 insertions(+), 2 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 39183d9977d1..713703c03173 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1313,6 +1313,65 @@ static const struct file_operations proc_oom_score_adj_operations = { .llseek = default_llseek, }; +#ifdef CONFIG_MAX_MAP_COUNT +static ssize_t proc_max_map_count_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file_inode(file)); + char buffer[PROC_NUMBUF]; + int max_map_count = 0; + size_t len; + + if (!task) + return -ESRCH; + if (!task->mm) + goto out; + max_map_count = task->mm->max_map_count; +out: + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", max_map_count); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static ssize_t proc_max_map_count_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int max_map_count; + int err; + + memset(buffer, 0, sizeof(buffer)); + + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + err = kstrtoint(strstrip(buffer), 0, &max_map_count); + if (err < 0) + return err; + + if (max_map_count != 0) + return -EINVAL; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + if (!task->mm) + goto out; + task->mm->max_map_count = max_map_count; +out: + put_task_struct(task); + return count; +} + +static const struct file_operations proc_max_map_count_operations = { + .read = proc_max_map_count_read, + .write = proc_max_map_count_write, + .llseek = generic_file_llseek, +}; +#endif + #ifdef CONFIG_AUDIT #define TMPBUFLEN 11 static ssize_t proc_loginuid_read(struct file * file, char __user * buf, @@ -2726,7 +2785,7 @@ static struct dentry *proc_pident_instantiate(struct dentry *dentry, return d_splice_alias(inode, dentry); } -static struct dentry *proc_pident_lookup(struct inode *dir, +static struct dentry *proc_pident_lookup(struct inode *dir, struct dentry *dentry, const struct pid_entry *p, const struct pid_entry *end) @@ -2939,7 +2998,7 @@ static const struct pid_entry attr_dir_stuff[] = { static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) { - return proc_pident_readdir(file, ctx, + return proc_pident_readdir(file, ctx, attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); } @@ -3381,6 +3440,9 @@ static const struct pid_entry tgid_base_stuff[] = { ONE("oom_score", S_IRUGO, proc_oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), +#ifdef CONFIG_MAX_MAP_COUNT + REG("max_map_count", S_IRUGO|S_IWUSR, proc_max_map_count_operations), +#endif #ifdef CONFIG_AUDIT REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), @@ -3731,6 +3793,9 @@ static const struct pid_entry tid_base_stuff[] = { ONE("oom_score", S_IRUGO, proc_oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), +#ifdef CONFIG_MAX_MAP_COUNT + REG("max_map_count", S_IRUGO|S_IWUSR, proc_max_map_count_operations), +#endif #ifdef CONFIG_AUDIT REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index afadea7c21e0..7984bb8b7ae6 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -856,6 +856,9 @@ struct mm_struct { atomic_long_t pgtables_bytes; /* size of all page tables */ #endif int map_count; /* number of VMAs */ +#ifdef CONFIG_MAX_MAP_COUNT + int max_map_count; /* number of max VMAs */ +#endif spinlock_t page_table_lock; /* Protects page tables and some * counters diff --git a/kernel/fork.c b/kernel/fork.c index bd1500d4a03b..2dc0d5e1759c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -774,6 +774,10 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, goto fail_nomem_vmi_store; mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (mm->map_count > mm->max_map_count) + mm->max_map_count = mm->map_count; +#endif if (!(tmp->vm_flags & VM_WIPEONFORK)) { if (async_fork) retval = async_fork_cpr_fast(tmp, mpnt); @@ -1784,6 +1788,9 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk) mm = dup_mm(tsk, current->mm); if (!mm) return -ENOMEM; +#ifdef CONFIG_MAX_MAP_COUNT + mm->max_map_count = 0; +#endif } tsk->mm = mm; diff --git a/mm/Kconfig b/mm/Kconfig index 7f159aeb2bfe..1b192386b0bd 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1402,4 +1402,9 @@ config RECLAIM_COLDPGS will be reclaimed so that they can be reused by somebody else, like newly created cgroups to increase the whole system density. +config MAX_MAP_COUNT + bool "Show max map count for a task" + default n + help + show max map count for a task, and can only be set 0. endmenu diff --git a/mm/mmap.c b/mm/mmap.c index 5d8e10f37890..9e57e1bb9ec7 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -468,6 +468,10 @@ static int vma_link(struct mm_struct *mm, struct vm_area_struct *vma) } mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (mm->map_count > mm->max_map_count) + mm->max_map_count = mm->map_count; +#endif validate_mm(mm); return 0; } @@ -586,6 +590,10 @@ static inline void vma_complete(struct vma_prepare *vp, */ vma_iter_store(vmi, vp->insert); mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (mm->map_count > mm->max_map_count) + mm->max_map_count = mm->map_count; +#endif } if (vp->anon_vma) { @@ -2925,6 +2933,10 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, vma_start_write(vma); vma_iter_store(&vmi, vma); mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (mm->map_count > mm->max_map_count) + mm->max_map_count = mm->map_count; +#endif if (vma->vm_file) { i_mmap_lock_write(vma->vm_file->f_mapping); if (vma->vm_flags & VM_SHARED) @@ -3282,6 +3294,10 @@ static int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma, goto mas_store_fail; mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (mm->map_count > mm->max_map_count) + mm->max_map_count = mm->map_count; +#endif validate_mm(mm); ksm_add_vma(vma); out: diff --git a/mm/nommu.c b/mm/nommu.c index 3228b2d3e4ab..a39c7e9254d6 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1208,6 +1208,10 @@ unsigned long do_mmap(struct file *file, setup_vma_to_mm(vma, current->mm); current->mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (current->mm->map_count > current->mm->max_map_count) + current->mm->max_map_count = current->mm->map_count; +#endif /* add the VMA to the tree */ vma_iter_store(&vmi, vma); @@ -1376,6 +1380,10 @@ int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, setup_vma_to_mm(new, mm); vma_iter_store(vmi, new); mm->map_count++; +#ifdef CONFIG_MAX_MAP_COUNT + if (mm->map_count > mm->max_map_count) + mm->max_map_count = mm->map_count; +#endif return 0; err_vmi_preallocate: -- Gitee