Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 365431
b: refs/heads/master
c: c9b1d09
h: refs/heads/master
i:
  365429: 23b97e4
  365427: 2ebebbf
  365423: 28ed105
v: v3
  • Loading branch information
Andrew Shewmaker authored and Linus Torvalds committed Apr 29, 2013
1 parent df8636b commit 868bd4a
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d8f10cb3d375c34ad668f32ca6e4661ad1fc23b2
refs/heads/master: c9b1d0981fcce3d9976d7b7a56e4e0503bc610dd
20 changes: 20 additions & 0 deletions trunk/Documentation/sysctl/vm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Currently, these files are in /proc/sys/vm:
- percpu_pagelist_fraction
- stat_interval
- swappiness
- user_reserve_kbytes
- vfs_cache_pressure
- zone_reclaim_mode

Expand Down Expand Up @@ -542,6 +543,7 @@ memory until it actually runs out.

When this flag is 2, the kernel uses a "never overcommit"
policy that attempts to prevent any overcommit of memory.
Note that user_reserve_kbytes affects this policy.

This feature can be very useful because there are a lot of
programs that malloc() huge amounts of memory "just-in-case"
Expand Down Expand Up @@ -645,6 +647,24 @@ The default value is 60.

==============================================================

- user_reserve_kbytes

When overcommit_memory is set to 2, "never overommit" mode, reserve
min(3% of current process size, user_reserve_kbytes) of free memory.
This is intended to prevent a user from starting a single memory hogging
process, such that they cannot recover (kill the hog).

user_reserve_kbytes defaults to min(3% of the current process size, 128MB).

If this is reduced to zero, then the user will be allowed to allocate
all free memory with a single process, minus admin_reserve_kbytes.
Any subsequent attempts to execute a command will result in
"fork: Cannot allocate memory".

Changing this takes effect whenever an application requests memory.

==============================================================

vfs_cache_pressure
------------------

Expand Down
8 changes: 7 additions & 1 deletion trunk/Documentation/vm/overcommit-accounting
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ The Linux kernel supports the following overcommit handling modes
default.

1 - Always overcommit. Appropriate for some scientific
applications.
applications. Classic example is code using sparse arrays
and just relying on the virtual memory consisting almost
entirely of zero pages.

2 - Don't overcommit. The total address space commit
for the system is not permitted to exceed swap + a
Expand All @@ -18,6 +20,10 @@ The Linux kernel supports the following overcommit handling modes
pages but will receive errors on memory allocation as
appropriate.

Useful for applications that want to guarantee their
memory allocations will be available in the future
without having to initialize every page.

The overcommit policy is set via the sysctl `vm.overcommit_memory'.

The overcommit percentage is set via `vm.overcommit_ratio'.
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ extern int sysctl_legacy_va_layout;
#include <asm/pgtable.h>
#include <asm/processor.h>

extern unsigned long sysctl_user_reserve_kbytes;

#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n))

/* to align the pointer to the (next) page boundary */
Expand Down
7 changes: 7 additions & 0 deletions trunk/kernel/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,13 @@ static struct ctl_table vm_table[] = {
.extra2 = &one,
},
#endif
{
.procname = "user_reserve_kbytes",
.data = &sysctl_user_reserve_kbytes,
.maxlen = sizeof(sysctl_user_reserve_kbytes),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
{ }
};

Expand Down
35 changes: 30 additions & 5 deletions trunk/mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ EXPORT_SYMBOL(vm_get_page_prot);
int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS; /* heuristic overcommit */
int sysctl_overcommit_ratio __read_mostly = 50; /* default is 50% */
int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
/*
* Make sure vm_committed_as in one cacheline and not cacheline shared with
* other variables. It can be updated by several CPUs frequently.
Expand Down Expand Up @@ -122,7 +123,7 @@ EXPORT_SYMBOL_GPL(vm_memory_committed);
*/
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
{
unsigned long free, allowed;
unsigned long free, allowed, reserve;

vm_acct_memory(pages);

Expand Down Expand Up @@ -183,10 +184,13 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
allowed -= allowed / 32;
allowed += total_swap_pages;

/* Don't let a single process grow too big:
leave 3% of the size of this process for other processes */
if (mm)
allowed -= mm->total_vm / 32;
/*
* Don't let a single process grow so big a user can't recover
*/
if (mm) {
reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
allowed -= min(mm->total_vm / 32, reserve);
}

if (percpu_counter_read_positive(&vm_committed_as) < allowed)
return 0;
Expand Down Expand Up @@ -3094,3 +3098,24 @@ void __init mmap_init(void)
ret = percpu_counter_init(&vm_committed_as, 0);
VM_BUG_ON(ret);
}

/*
* Initialise sysctl_user_reserve_kbytes.
*
* This is intended to prevent a user from starting a single memory hogging
* process, such that they cannot recover (kill the hog) in OVERCOMMIT_NEVER
* mode.
*
* The default value is min(3% of free memory, 128MB)
* 128MB is enough to recover with sshd/login, bash, and top/kill.
*/
static int __meminit init_user_reserve(void)
{
unsigned long free_kbytes;

free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);

sysctl_user_reserve_kbytes = min(free_kbytes / 32, 1UL << 17);
return 0;
}
module_init(init_user_reserve)
35 changes: 30 additions & 5 deletions trunk/mm/nommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
int sysctl_overcommit_ratio = 50; /* default is 50% */
int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
int heap_stack_gap = 0;

atomic_long_t mmap_pages_allocated;
Expand Down Expand Up @@ -1897,7 +1898,7 @@ EXPORT_SYMBOL(unmap_mapping_range);
*/
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
{
unsigned long free, allowed;
unsigned long free, allowed, reserve;

vm_acct_memory(pages);

Expand Down Expand Up @@ -1957,10 +1958,13 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
allowed -= allowed / 32;
allowed += total_swap_pages;

/* Don't let a single process grow too big:
leave 3% of the size of this process for other processes */
if (mm)
allowed -= mm->total_vm / 32;
/*
* Don't let a single process grow so big a user can't recover
*/
if (mm) {
reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
allowed -= min(mm->total_vm / 32, reserve);
}

if (percpu_counter_read_positive(&vm_committed_as) < allowed)
return 0;
Expand Down Expand Up @@ -2122,3 +2126,24 @@ int nommu_shrink_inode_mappings(struct inode *inode, size_t size,
up_write(&nommu_region_sem);
return 0;
}

/*
* Initialise sysctl_user_reserve_kbytes.
*
* This is intended to prevent a user from starting a single memory hogging
* process, such that they cannot recover (kill the hog) in OVERCOMMIT_NEVER
* mode.
*
* The default value is min(3% of free memory, 128MB)
* 128MB is enough to recover with sshd/login, bash, and top/kill.
*/
static int __meminit init_user_reserve(void)
{
unsigned long free_kbytes;

free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);

sysctl_user_reserve_kbytes = min(free_kbytes / 32, 1UL << 17);
return 0;
}
module_init(init_user_reserve)

0 comments on commit 868bd4a

Please sign in to comment.