mm: deduplicate memory overcommitment code
Currently we have two copies of the same code which implements memory overcommitment logic. Let's move it into mm/util.c and hence avoid duplication. No functional changes here. Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
ea606cf5d8
commit
39a1aa8e19
124
mm/mmap.c
124
mm/mmap.c
|
@ -122,130 +122,6 @@ void vma_set_page_prot(struct vm_area_struct *vma)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS; /* heuristic overcommit */
|
|
||||||
int sysctl_overcommit_ratio __read_mostly = 50; /* default is 50% */
|
|
||||||
unsigned long sysctl_overcommit_kbytes __read_mostly;
|
|
||||||
int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
|
|
||||||
unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
|
|
||||||
unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
|
|
||||||
/*
|
|
||||||
* Make sure vm_committed_as in one cacheline and not cacheline shared with
|
|
||||||
* other variables. It can be updated by several CPUs frequently.
|
|
||||||
*/
|
|
||||||
struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The global memory commitment made in the system can be a metric
|
|
||||||
* that can be used to drive ballooning decisions when Linux is hosted
|
|
||||||
* as a guest. On Hyper-V, the host implements a policy engine for dynamically
|
|
||||||
* balancing memory across competing virtual machines that are hosted.
|
|
||||||
* Several metrics drive this policy engine including the guest reported
|
|
||||||
* memory commitment.
|
|
||||||
*/
|
|
||||||
unsigned long vm_memory_committed(void)
|
|
||||||
{
|
|
||||||
return percpu_counter_read_positive(&vm_committed_as);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(vm_memory_committed);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check that a process has enough memory to allocate a new virtual
|
|
||||||
* mapping. 0 means there is enough memory for the allocation to
|
|
||||||
* succeed and -ENOMEM implies there is not.
|
|
||||||
*
|
|
||||||
* We currently support three overcommit policies, which are set via the
|
|
||||||
* vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting
|
|
||||||
*
|
|
||||||
* Strict overcommit modes added 2002 Feb 26 by Alan Cox.
|
|
||||||
* Additional code 2002 Jul 20 by Robert Love.
|
|
||||||
*
|
|
||||||
* cap_sys_admin is 1 if the process has admin privileges, 0 otherwise.
|
|
||||||
*
|
|
||||||
* Note this is a helper function intended to be used by LSMs which
|
|
||||||
* wish to use this logic.
|
|
||||||
*/
|
|
||||||
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
|
|
||||||
{
|
|
||||||
long free, allowed, reserve;
|
|
||||||
|
|
||||||
VM_WARN_ONCE(percpu_counter_read(&vm_committed_as) <
|
|
||||||
-(s64)vm_committed_as_batch * num_online_cpus(),
|
|
||||||
"memory commitment underflow");
|
|
||||||
|
|
||||||
vm_acct_memory(pages);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sometimes we want to use more memory than we have
|
|
||||||
*/
|
|
||||||
if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
|
|
||||||
free = global_page_state(NR_FREE_PAGES);
|
|
||||||
free += global_page_state(NR_FILE_PAGES);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* shmem pages shouldn't be counted as free in this
|
|
||||||
* case, they can't be purged, only swapped out, and
|
|
||||||
* that won't affect the overall amount of available
|
|
||||||
* memory in the system.
|
|
||||||
*/
|
|
||||||
free -= global_page_state(NR_SHMEM);
|
|
||||||
|
|
||||||
free += get_nr_swap_pages();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Any slabs which are created with the
|
|
||||||
* SLAB_RECLAIM_ACCOUNT flag claim to have contents
|
|
||||||
* which are reclaimable, under pressure. The dentry
|
|
||||||
* cache and most inode caches should fall into this
|
|
||||||
*/
|
|
||||||
free += global_page_state(NR_SLAB_RECLAIMABLE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Leave reserved pages. The pages are not for anonymous pages.
|
|
||||||
*/
|
|
||||||
if (free <= totalreserve_pages)
|
|
||||||
goto error;
|
|
||||||
else
|
|
||||||
free -= totalreserve_pages;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reserve some for root
|
|
||||||
*/
|
|
||||||
if (!cap_sys_admin)
|
|
||||||
free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
|
|
||||||
|
|
||||||
if (free > pages)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
allowed = vm_commit_limit();
|
|
||||||
/*
|
|
||||||
* Reserve some for root
|
|
||||||
*/
|
|
||||||
if (!cap_sys_admin)
|
|
||||||
allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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_t(long, mm->total_vm / 32, reserve);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (percpu_counter_read_positive(&vm_committed_as) < allowed)
|
|
||||||
return 0;
|
|
||||||
error:
|
|
||||||
vm_unacct_memory(pages);
|
|
||||||
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Requires inode->i_mapping->i_mmap_rwsem
|
* Requires inode->i_mapping->i_mmap_rwsem
|
||||||
*/
|
*/
|
||||||
|
|
116
mm/nommu.c
116
mm/nommu.c
|
@ -47,33 +47,11 @@ struct page *mem_map;
|
||||||
unsigned long max_mapnr;
|
unsigned long max_mapnr;
|
||||||
EXPORT_SYMBOL(max_mapnr);
|
EXPORT_SYMBOL(max_mapnr);
|
||||||
unsigned long highest_memmap_pfn;
|
unsigned long highest_memmap_pfn;
|
||||||
struct percpu_counter vm_committed_as;
|
|
||||||
int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
|
|
||||||
int sysctl_overcommit_ratio = 50; /* default is 50% */
|
|
||||||
unsigned long sysctl_overcommit_kbytes __read_mostly;
|
|
||||||
int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
|
|
||||||
int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
|
int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
|
||||||
unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
|
|
||||||
unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
|
|
||||||
int heap_stack_gap = 0;
|
int heap_stack_gap = 0;
|
||||||
|
|
||||||
atomic_long_t mmap_pages_allocated;
|
atomic_long_t mmap_pages_allocated;
|
||||||
|
|
||||||
/*
|
|
||||||
* The global memory commitment made in the system can be a metric
|
|
||||||
* that can be used to drive ballooning decisions when Linux is hosted
|
|
||||||
* as a guest. On Hyper-V, the host implements a policy engine for dynamically
|
|
||||||
* balancing memory across competing virtual machines that are hosted.
|
|
||||||
* Several metrics drive this policy engine including the guest reported
|
|
||||||
* memory commitment.
|
|
||||||
*/
|
|
||||||
unsigned long vm_memory_committed(void)
|
|
||||||
{
|
|
||||||
return percpu_counter_read_positive(&vm_committed_as);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(vm_memory_committed);
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(mem_map);
|
EXPORT_SYMBOL(mem_map);
|
||||||
|
|
||||||
/* list of mapped, potentially shareable regions */
|
/* list of mapped, potentially shareable regions */
|
||||||
|
@ -1828,100 +1806,6 @@ void unmap_mapping_range(struct address_space *mapping,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(unmap_mapping_range);
|
EXPORT_SYMBOL(unmap_mapping_range);
|
||||||
|
|
||||||
/*
|
|
||||||
* Check that a process has enough memory to allocate a new virtual
|
|
||||||
* mapping. 0 means there is enough memory for the allocation to
|
|
||||||
* succeed and -ENOMEM implies there is not.
|
|
||||||
*
|
|
||||||
* We currently support three overcommit policies, which are set via the
|
|
||||||
* vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting
|
|
||||||
*
|
|
||||||
* Strict overcommit modes added 2002 Feb 26 by Alan Cox.
|
|
||||||
* Additional code 2002 Jul 20 by Robert Love.
|
|
||||||
*
|
|
||||||
* cap_sys_admin is 1 if the process has admin privileges, 0 otherwise.
|
|
||||||
*
|
|
||||||
* Note this is a helper function intended to be used by LSMs which
|
|
||||||
* wish to use this logic.
|
|
||||||
*/
|
|
||||||
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
|
|
||||||
{
|
|
||||||
long free, allowed, reserve;
|
|
||||||
|
|
||||||
vm_acct_memory(pages);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sometimes we want to use more memory than we have
|
|
||||||
*/
|
|
||||||
if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
|
|
||||||
free = global_page_state(NR_FREE_PAGES);
|
|
||||||
free += global_page_state(NR_FILE_PAGES);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* shmem pages shouldn't be counted as free in this
|
|
||||||
* case, they can't be purged, only swapped out, and
|
|
||||||
* that won't affect the overall amount of available
|
|
||||||
* memory in the system.
|
|
||||||
*/
|
|
||||||
free -= global_page_state(NR_SHMEM);
|
|
||||||
|
|
||||||
free += get_nr_swap_pages();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Any slabs which are created with the
|
|
||||||
* SLAB_RECLAIM_ACCOUNT flag claim to have contents
|
|
||||||
* which are reclaimable, under pressure. The dentry
|
|
||||||
* cache and most inode caches should fall into this
|
|
||||||
*/
|
|
||||||
free += global_page_state(NR_SLAB_RECLAIMABLE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Leave reserved pages. The pages are not for anonymous pages.
|
|
||||||
*/
|
|
||||||
if (free <= totalreserve_pages)
|
|
||||||
goto error;
|
|
||||||
else
|
|
||||||
free -= totalreserve_pages;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reserve some for root
|
|
||||||
*/
|
|
||||||
if (!cap_sys_admin)
|
|
||||||
free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
|
|
||||||
|
|
||||||
if (free > pages)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
allowed = vm_commit_limit();
|
|
||||||
/*
|
|
||||||
* Reserve some 3% for root
|
|
||||||
*/
|
|
||||||
if (!cap_sys_admin)
|
|
||||||
allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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_t(long, mm->total_vm / 32, reserve);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (percpu_counter_read_positive(&vm_committed_as) < allowed)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
vm_unacct_memory(pages);
|
|
||||||
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||||
{
|
{
|
||||||
BUG();
|
BUG();
|
||||||
|
|
124
mm/util.c
124
mm/util.c
|
@ -396,6 +396,13 @@ int __page_mapcount(struct page *page)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__page_mapcount);
|
EXPORT_SYMBOL_GPL(__page_mapcount);
|
||||||
|
|
||||||
|
int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS;
|
||||||
|
int sysctl_overcommit_ratio __read_mostly = 50;
|
||||||
|
unsigned long sysctl_overcommit_kbytes __read_mostly;
|
||||||
|
int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
|
||||||
|
unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
|
||||||
|
unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
|
||||||
|
|
||||||
int overcommit_ratio_handler(struct ctl_table *table, int write,
|
int overcommit_ratio_handler(struct ctl_table *table, int write,
|
||||||
void __user *buffer, size_t *lenp,
|
void __user *buffer, size_t *lenp,
|
||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
|
@ -437,6 +444,123 @@ unsigned long vm_commit_limit(void)
|
||||||
return allowed;
|
return allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure vm_committed_as in one cacheline and not cacheline shared with
|
||||||
|
* other variables. It can be updated by several CPUs frequently.
|
||||||
|
*/
|
||||||
|
struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The global memory commitment made in the system can be a metric
|
||||||
|
* that can be used to drive ballooning decisions when Linux is hosted
|
||||||
|
* as a guest. On Hyper-V, the host implements a policy engine for dynamically
|
||||||
|
* balancing memory across competing virtual machines that are hosted.
|
||||||
|
* Several metrics drive this policy engine including the guest reported
|
||||||
|
* memory commitment.
|
||||||
|
*/
|
||||||
|
unsigned long vm_memory_committed(void)
|
||||||
|
{
|
||||||
|
return percpu_counter_read_positive(&vm_committed_as);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vm_memory_committed);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that a process has enough memory to allocate a new virtual
|
||||||
|
* mapping. 0 means there is enough memory for the allocation to
|
||||||
|
* succeed and -ENOMEM implies there is not.
|
||||||
|
*
|
||||||
|
* We currently support three overcommit policies, which are set via the
|
||||||
|
* vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting
|
||||||
|
*
|
||||||
|
* Strict overcommit modes added 2002 Feb 26 by Alan Cox.
|
||||||
|
* Additional code 2002 Jul 20 by Robert Love.
|
||||||
|
*
|
||||||
|
* cap_sys_admin is 1 if the process has admin privileges, 0 otherwise.
|
||||||
|
*
|
||||||
|
* Note this is a helper function intended to be used by LSMs which
|
||||||
|
* wish to use this logic.
|
||||||
|
*/
|
||||||
|
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
|
||||||
|
{
|
||||||
|
long free, allowed, reserve;
|
||||||
|
|
||||||
|
VM_WARN_ONCE(percpu_counter_read(&vm_committed_as) <
|
||||||
|
-(s64)vm_committed_as_batch * num_online_cpus(),
|
||||||
|
"memory commitment underflow");
|
||||||
|
|
||||||
|
vm_acct_memory(pages);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sometimes we want to use more memory than we have
|
||||||
|
*/
|
||||||
|
if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
|
||||||
|
free = global_page_state(NR_FREE_PAGES);
|
||||||
|
free += global_page_state(NR_FILE_PAGES);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* shmem pages shouldn't be counted as free in this
|
||||||
|
* case, they can't be purged, only swapped out, and
|
||||||
|
* that won't affect the overall amount of available
|
||||||
|
* memory in the system.
|
||||||
|
*/
|
||||||
|
free -= global_page_state(NR_SHMEM);
|
||||||
|
|
||||||
|
free += get_nr_swap_pages();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Any slabs which are created with the
|
||||||
|
* SLAB_RECLAIM_ACCOUNT flag claim to have contents
|
||||||
|
* which are reclaimable, under pressure. The dentry
|
||||||
|
* cache and most inode caches should fall into this
|
||||||
|
*/
|
||||||
|
free += global_page_state(NR_SLAB_RECLAIMABLE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Leave reserved pages. The pages are not for anonymous pages.
|
||||||
|
*/
|
||||||
|
if (free <= totalreserve_pages)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
free -= totalreserve_pages;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserve some for root
|
||||||
|
*/
|
||||||
|
if (!cap_sys_admin)
|
||||||
|
free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
|
||||||
|
|
||||||
|
if (free > pages)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
allowed = vm_commit_limit();
|
||||||
|
/*
|
||||||
|
* Reserve some for root
|
||||||
|
*/
|
||||||
|
if (!cap_sys_admin)
|
||||||
|
allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_t(long, mm->total_vm / 32, reserve);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (percpu_counter_read_positive(&vm_committed_as) < allowed)
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
vm_unacct_memory(pages);
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get_cmdline() - copy the cmdline value to a buffer.
|
* get_cmdline() - copy the cmdline value to a buffer.
|
||||||
* @task: the task whose cmdline value to copy.
|
* @task: the task whose cmdline value to copy.
|
||||||
|
|
Loading…
Reference in New Issue