strict overcommit
Subsystems (10)
PATCH 9/13 strict overcommit
Alan's overcommit patch, brought to 2.5 by Robert Love.
Can't say I've tested its functionality at all, but it doesn't crash, it has been in -ac and RH kernels for some time and I haven't observed any of its functions on profiles.
"So what is strict VM overcommit? We introduce new overcommit
policies that attempt to never succeed an allocation that can not be fulfilled by the backing store and consequently never OOM. This is achieved through strict accounting of the committed address space and a policy to allow/refuse allocations based on that accounting.
In the strictest of modes, it should be impossible to allocate more memory than available and impossible to OOM. All memory failures should be pushed down to the allocation routines -- malloc, mmap, etc.
The new modes are available via sysctl (same as before). See Documentation/vm/overcommit-accounting for more information."
Documentation/sysctl/vm.txt | 16 ++ Documentation/vm/overcommit-accounting | 70 ++++++++++ fs/exec.c | 9 + fs/proc/proc_misc.c | 7 - include/linux/mm.h | 32 ---- include/linux/mman.h | 3 include/linux/sysctl.h | 1 ipc/shm.c | 2 kernel/fork.c | 18 ++ kernel/sysctl.c | 4 mm/mmap.c | 219 ++++++++++++++++++++++++--------- mm/mprotect.c | 17 ++ mm/mremap.c | 37 +++-- mm/shmem.c | 61 ++++++++- 14 files changed, 386 insertions(+), 110 deletions(-)
Documentation/sysctl/vm.txt renamed from Documentation/sysctl/vm.txt~overcommit +15 -1
@@ -78,7 +78,21 @@ This feature can be very useful because programs that malloc() huge amounts of memory "just-in-case" and don't use much of it. -Look at: mm/mmap.c::vm_enough_memory() for more information. +A value of 2 introduces a new "strict overcommit" policy +that attempts to prevent any overcommit of memory. + +The default value is 0. + +See Documentation/vm/overcommit-accounting and +mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +overcommit_ratio: + +When overcommit_memory is set to 2, the committed address +space is not permitted to exceed swap plus this percentage +of physical RAM. See above. ==============================================================
Documentation/vm/overcommit-accounting new file +70 -0
70 lines not on this page · raw message
fs/exec.c renamed from fs/exec.c~overcommit +7 -2
@@ -313,8 +313,13 @@ int setup_arg_pages(struct linux_binprm mpnt =kmem_cache_alloc (vm_area_cachep,SLAB_KERNEL );if (!mpnt) -return -ENOMEM ; - +return -ENOMEM ; + +if (!vm_enough_memory ((STACK_TOP - (PAGE_MASK & (unsigned long ) bprm->p))>>PAGE_SHIFT )) { +kmem_cache_free (vm_area_cachep, mpnt); +return -ENOMEM ; + } +down_write (¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm;
fs/proc/proc_misc.c renamed from fs/proc/proc_misc.c~overcommit +6 -1
@@ -126,11 +126,13 @@ static int uptime_read_proc(char *page,return proc_calc_metrics (page, start, off, count, eof, len); } +extern atomic_t vm_committed_space; +static int meminfo_read_proc (char *page,char **start,off_t off,int count,int *eof,void *data) {struct sysinfo i; -int len; +int len, committed;struct page_state ps;get_page_state (&ps);
@@ -140,6 +142,7 @@ static int meminfo_read_proc(char *page,#define K (x) ((x) << (PAGE_SHIFT - 10))si_meminfo (&i);si_swapinfo (&i); + committed =atomic_read (&vm_committed_space);/* * Tagged format, for easy grepping and expansion.
@@ -160,6 +163,7 @@ static int meminfo_read_proc(char *page,"SwapFree: %8lu kB\n" "Dirty: %8lu kB\n" "Writeback: %8lu kB\n" +"Committed_AS: %8u kB\n" "PageTables: %8lu kB\n" "ReverseMaps: %8lu\n" , K(i.totalram),
@@ -177,6 +181,7 @@ static int meminfo_read_proc(char *page,K (i.freeswap),K (ps.nr_dirty),K (ps.nr_writeback), +K (committed),K (ps.nr_page_table_pages), ps.nr_reverse_maps );
include/linux/mman.h renamed from include/linux/mman.h~overcommit +3 -0
@@ -6,4 +6,7 @@#define MREMAP_MAYMOVE 1#define MREMAP_FIXED 2 +extern int vm_enough_memory (long pages); +extern void vm_unacct_memory (long pages); +#endif /* _LINUX_MMAN_H */
include/linux/mm.h renamed from include/linux/mm.h~overcommit +5 -27
@@ -103,8 +103,9 @@ struct vm_area_struct {#define VM_DONTCOPY 0x00020000/* Do not copy this vma on fork */ #define VM_DONTEXPAND 0x00040000/* Cannot expand with mremap() */ #define VM_RESERVED 0x00080000/* Don't unmap it from swap_out */ +#define VM_ACCOUNT 0x00100000/* Is a VM accounted object */ -#define VM_STACK_FLAGS (0x00000100 | VM_DATA_DEFAULT_FLAGS) +#define VM_STACK_FLAGS (0x00000100 | VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT)#define VM_READHINTMASK (VM_SEQ_READ | VM_RAND_READ)#define VM_ClearReadHint (v) (v)->vm_flags &= ~VM_READHINTMASK
@@ -429,7 +430,7 @@ out:return ret; } -extern int do_munmap (struct mm_struct *,unsigned long ,size_t ); +extern int do_munmap (struct mm_struct *,unsigned long ,size_t ,int );extern unsigned long do_brk (unsigned long ,unsigned long );
@@ -471,31 +472,8 @@ void page_cache_readahead(struct file *fvoid page_cache_readaround (struct file *file,unsigned long offset);void handle_ra_miss (struct file *file); -/* vma is the first one with address < vma->vm_end, -* and even address < vma->vm_start. Have to extend vma. */ -static inline int expand_stack (struct vm_area_struct * vma,unsigned long address) -{ -unsigned long grow; - -/* -* vma->vm_start/vm_end cannot change under us because the caller is required -* to hold the mmap_sem in write mode. We need to get the spinlock only -* before relocating the vma range ourself. -*/ - address &=PAGE_MASK ; - grow = (vma->vm_start - address) >>PAGE_SHIFT ; -if (vma->vm_end - address > current->rlim[RLIMIT_STACK ].rlim_cur || - ((vma->vm_mm->total_vm + grow) <<PAGE_SHIFT ) > current->rlim[RLIMIT_AS ].rlim_cur) -return -ENOMEM ; -spin_lock (&vma->vm_mm->page_table_lock); - vma->vm_start = address; - vma->vm_pgoff -= grow; - vma->vm_mm->total_vm += grow; -if (vma->vm_flags &VM_LOCKED ) - vma->vm_mm->locked_vm += grow; -spin_unlock (&vma->vm_mm->page_table_lock); -return 0 ; -} +/* Do stack extension */ +extern int expand_stack (struct vm_area_struct * vma,unsigned long address);/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ extern struct vm_area_struct *find_vma (struct mm_struct * mm,unsigned long addr);
include/linux/sysctl.h renamed from include/linux/sysctl.h~overcommit +1 -0
@@ -149,6 +149,7 @@ enumVM_DIRTY_WB_CS =14 ,/* dirty_writeback_centisecs */ VM_DIRTY_EXPIRE_CS =15 ,/* dirty_expire_centisecs */ VM_NR_PDFLUSH_THREADS =16 ,/* nr_pdflush_threads */ + VM_OVERCOMMIT_RATIO=17, /* percent of RAM to allow overcommit in */ };
ipc/shm.c renamed from ipc/shm.c~overcommit +1 -1
@@ -671,7 +671,7 @@ asmlinkage long sys_shmdt (char *shmaddr shmdnext = shmd->vm_next;if (shmd->vm_ops == &shm_vm_ops && shmd->vm_start - (shmd->vm_pgoff <<PAGE_SHIFT ) == (ulong ) shmaddr) { -do_munmap (mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); +do_munmap (mm, shmd->vm_start, shmd->vm_end - shmd->vm_start,1 ); retval =0 ; } }
kernel/fork.c renamed from kernel/fork.c~overcommit +17 -1
@@ -23,6 +23,7 @@#include <linux/personality.h> #include <linux/file.h> #include <linux/binfmts.h> +#include <linux/mman.h> #include <linux/fs.h> #include <linux/security.h>
@@ -181,6 +182,7 @@ static inline int dup_mmap(struct mm_str {struct vm_area_struct * mpnt, *tmp, **pprev;int retval; +unsigned long charge =0 ;flush_cache_mm (current->mm); mm->locked_vm =0 ;
@@ -208,6 +210,17 @@ static inline int dup_mmap(struct mm_str retval = -ENOMEM ;if (mpnt->vm_flags &VM_DONTCOPY )continue ; + +/* +* FIXME: shared writable map accounting should be one off +*/ +if (mpnt->vm_flags &VM_ACCOUNT ) { +unsigned int len = (mpnt->vm_end - mpnt->vm_start) >>PAGE_SHIFT ; +if (!vm_enough_memory (len)) + goto fail_nomem; + charge += len; + } + tmp =kmem_cache_alloc (vm_area_cachep,SLAB_KERNEL );if (!tmp) goto fail_nomem;
@@ -248,9 +261,12 @@ static inline int dup_mmap(struct mm_str retval =0 ;build_mmap_rb (mm); -fail_nomem: +out:flush_tlb_mm (current->mm);return retval; +fail_nomem: +vm_unacct_memory (charge); + goto out; } spinlock_t mmlist_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
kernel/sysctl.c renamed from kernel/sysctl.c~overcommit +4 -0
@@ -45,6 +45,7 @@extern int panic_timeout;extern int C_A_D ;extern int sysctl_overcommit_memory; +extern int sysctl_overcommit_ratio;extern int max_threads;extern atomic_t nr_queued_signals;extern int max_queued_signals;
@@ -268,6 +269,9 @@ static int one_hundred = 100;static ctl_table vm_table[] = { {VM_OVERCOMMIT_MEMORY ,"overcommit_memory" , &sysctl_overcommit_memory,sizeof (sysctl_overcommit_memory),0644 ,NULL , &proc_dointvec}, + {VM_OVERCOMMIT_RATIO ,"overcommit_ratio" , + &sysctl_overcommit_ratio,sizeof (sysctl_overcommit_ratio),0644 , +NULL , &proc_dointvec}, {VM_PAGERDAEMON ,"kswapd" , &pager_daemon,sizeof (pager_daemon_t),0644 ,NULL , &proc_dointvec}, {VM_PAGE_CLUSTER ,"page-cluster" ,
mm/mmap.c renamed from mm/mmap.c~overcommit +161 -58
365 lines not on this page · raw message
mm/mprotect.c renamed from mm/mprotect.c~overcommit +15 -2
@@ -1,7 +1,10 @@/* -* linux/mm/mprotect.c +* mm/mprotect.c * * (C) Copyright 1994 Linus Torvalds +* +* Address space accounting code <[email protected]> +* (C) Copyright 2002 Red Hat Inc, All Rights Reserved */ #include <linux/mm.h> #include <linux/slab.h>
@@ -248,6 +251,7 @@ static int mprotect_fixup(struct vm_area {pgprot_t newprot;int error; +unsigned long charged =0 ;if (newflags == vma->vm_flags) { *pprev = vma;
@@ -264,9 +268,18 @@ static int mprotect_fixup(struct vm_areaelse error =mprotect_fixup_middle (vma, pprev, start, end, newflags, newprot); -if (error) +if (error) { +if (newflags &PROT_WRITE ) +vm_unacct_memory (charged);return error; + } +/* +* Delayed accounting for reduction of memory use - done last to +* avoid allocation races +*/ +if (charged && !(newflags &PROT_WRITE )) +vm_unacct_memory (charged);change_protection (vma, start, end, newprot);return 0 ; }
mm/mremap.c renamed from mm/mremap.c~overcommit +26 -11
@@ -1,7 +1,10 @@/* -* linux/mm/remap.c +* mm/remap.c * * (C) Copyright 1996 Linus Torvalds +* +* Address space accounting code <[email protected]> +* (C) Copyright 2002 Red Hat Inc, All Rights Reserved */ #include <linux/mm.h>
@@ -18,8 +21,6 @@#include <asm/cacheflush.h> #include <asm/tlbflush.h> -extern int vm_enough_memory (long pages); -static inline pte_t *get_one_pte_map_nested (struct mm_struct *mm,unsigned long addr) {pgd_t * pgd;
@@ -209,7 +210,11 @@ static inline unsigned long move_vma(str new_vma->vm_ops->open (new_vma);insert_vm_struct (current->mm, new_vma); } -do_munmap (current->mm, addr, old_len); +/* +* The old VMA has been accounted for, +* don't double account +*/ +do_munmap (current->mm, addr, old_len,0 ); current->mm->total_vm += new_len >>PAGE_SHIFT ;if (new_vma->vm_flags &VM_LOCKED ) { current->mm->locked_vm += new_len >>PAGE_SHIFT ;
@@ -224,6 +229,8 @@ static inline unsigned long move_vma(strreturn -ENOMEM ; } +extern int sysctl_overcommit_memory;/* FIXME!! */ +/* * Expand (or shrink) an existing mapping, potentially moving it at the * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
@@ -237,6 +244,7 @@ unsigned long do_mremap(unsigned long ad {struct vm_area_struct *vma;unsigned long ret = -EINVAL ; +unsigned long charged =0 ;if (flags & ~(MREMAP_FIXED |MREMAP_MAYMOVE )) goto out;
@@ -266,16 +274,17 @@ unsigned long do_mremap(unsigned long adif ((addr <= new_addr) && (addr+old_len) > new_addr) goto out; -do_munmap (current->mm, new_addr, new_len); +do_munmap (current->mm, new_addr, new_len,1 ); }/* * Always allow a shrinking remap: that just unmaps * the unnecessary pages.. +* do_munmap does all the needed commit accounting */ ret = addr;if (old_len >= new_len) { -do_munmap (current->mm, addr+new_len, old_len - new_len); +do_munmap (current->mm, addr+new_len, old_len - new_len,1 );if (!(flags &MREMAP_FIXED ) || (new_addr == addr)) goto out; }
@@ -305,11 +314,14 @@ unsigned long do_mremap(unsigned long adif ((current->mm->total_vm <<PAGE_SHIFT ) + (new_len - old_len) > current->rlim[RLIMIT_AS ].rlim_cur) goto out; -/* Private writable mapping? Check memory availability.. */ -if ((vma->vm_flags & (VM_SHARED |VM_WRITE )) ==VM_WRITE && - !(flags &MAP_NORESERVE ) && - !vm_enough_memory ((new_len - old_len) >>PAGE_SHIFT )) - goto out; + +if (sysctl_overcommit_memory >1 ) + flags &= ~MAP_NORESERVE ; +if (vma->vm_flags &VM_ACCOUNT ) { + charged = (new_len - old_len) >>PAGE_SHIFT ; +if (!vm_enough_memory (charged)) + goto out_nc; + }/* old_len exactly to the end of the area.. * And we're not relocating the area.
@@ -356,6 +368,9 @@ unsigned long do_mremap(unsigned long ad ret =move_vma (vma, addr, old_len, new_len, new_addr); } out: +if (ret & ~PAGE_MASK ) +vm_unacct_memory (charged); +out_nc:return ret; }
mm/shmem.c renamed from mm/shmem.c~overcommit +55 -6
139 lines not on this page · raw message
.