diff --git a/fs/proc/base.c b/fs/proc/base.c index 39183d9977d17aa6997fdabe145f3c133b6248c2..713703c03173be6793342a48cb66d1d617a57c21 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 afadea7c21e0c5a376ae2f3043571e20e73c016e..7984bb8b7ae63e4db8fbbb9dd128e493d031dc30 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 bd1500d4a03bc65d7c7e404c967d3a80b766a66f..2dc0d5e1759c8f368609a9624cae91820a1c5e00 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 7f159aeb2bfeadcb2e07da13719471a35b1816f5..1b192386b0bd3e3d8e4d84080aa9194b2d217fa5 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 5d8e10f37890f724f8a7acc5ad54f43690e30697..9e57e1bb9ec79f1aafa3310f9efb324a2db1828b 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 3228b2d3e4ab6ce98eba03394e6b4d67da40fff6..a39c7e9254d682440d7da91e2d1c61538a0b8490 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: