]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Fix hugetlb-vs-memory overcommit
authorAndrew Morton <akpm@osdl.org>
Thu, 1 Apr 2004 05:51:13 +0000 (21:51 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 1 Apr 2004 05:51:13 +0000 (21:51 -0800)
From: Andy Whitcroft <apw@shadowen.org>

Two problems:

a) The memory overcommit code fails oto take into account all the pages
   which are pinned by being reserved for the hugetlbpage pool

b) We're performing overcommit accounting and checking on behalf of
   hugetlbpage vmas.

The main thrust is to ensure that VM_ACCOUNT actually only gets set on
vma's which are indeed accountable.  With that ensured much of the rest
comes out in the wash.  It also removes the hugetlb memory for the
overcommit_memory=2 case.

12 files changed:
arch/i386/mm/hugetlbpage.c
arch/ia64/mm/hugetlbpage.c
arch/ppc64/mm/hugetlbpage.c
arch/sh/mm/hugetlbpage.c
arch/sparc64/mm/hugetlbpage.c
include/linux/hugetlb.h
include/linux/mm.h
mm/mmap.c
mm/mprotect.c
security/commoncap.c
security/dummy.c
security/selinux/hooks.c

index 48deeb0caaf9461e0cbef4fa1baae19ea52b6651..32e7db2315fe93f0660ccce33bc1a9857b3a8b9f 100644 (file)
@@ -527,6 +527,12 @@ int is_hugepage_mem_enough(size_t size)
        return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpagemem;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+       return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
  * handle_mm_fault() to try to instantiate regular-sized pages in the
index 84db44246b448961a190d24247a6ccc1a2c20da4..a6c1ac69b6cdc9fed963d2c2c57f9e625f418900 100644 (file)
@@ -592,6 +592,12 @@ int is_hugepage_mem_enough(size_t size)
        return 1;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+       return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+
 static struct page *hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int *unused)
 {
        BUG();
index ed3d4ce2e5905ff794c42d4987ad07e33b31a5e1..8fd675fc2d8425603648f5558c39a15301054d54 100644 (file)
@@ -928,6 +928,12 @@ int is_hugepage_mem_enough(size_t size)
        return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpage_free;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+       return htlbpage_total * (HPAGE_SIZE / PAGE_SIZE);
+}
+
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
  * handle_mm_fault() to try to instantiate regular-sized pages in the
index f74d6de94ef63ab6954cbfa9d03cc7eec651ea4f..9065249a5765b530d5d7e17d07d3a6e1c90049c6 100644 (file)
@@ -501,6 +501,12 @@ int is_hugepage_mem_enough(size_t size)
        return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpagemem;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+       return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
  * handle_mm_fault() to try to instantiate regular-sized pages in the
index db74fddd5dc32e22b7c75c22565af614445fba90..6bb1cfd9009f64a49e2feaec2bb619ea36207275 100644 (file)
@@ -497,6 +497,12 @@ int is_hugepage_mem_enough(size_t size)
        return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpagemem;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+       return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
  * handle_mm_fault() to try to instantiate regular-sized pages in the
index 5075a90bcd65b4e7653499bfe89cd8253c5b4829..da3fc826a0de86ef01ed0c3a375890efabef51cb 100644 (file)
@@ -19,6 +19,7 @@ int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
 void huge_page_release(struct page *);
 int hugetlb_report_meminfo(char *);
 int is_hugepage_mem_enough(size_t);
+unsigned long hugetlb_total_pages(void);
 struct page *follow_huge_addr(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, int write);
 struct vm_area_struct *hugepage_vma(struct mm_struct *mm,
@@ -55,6 +56,10 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
        return 0;
 }
+static inline unsigned long hugetlb_total_pages(void)
+{
+       return 0;
+}
 
 #define follow_hugetlb_page(m,v,p,vs,a,b,i)    ({ BUG(); 0; })
 #define follow_huge_addr(mm, vma, addr, write) 0
index aaca9bd6ff8aa258b6ee32d570bef0a8e379272e..fbd569b35b4f894da5d68cb89605d797ced47952 100644 (file)
@@ -112,6 +112,9 @@ struct vm_area_struct {
 #define VM_HUGETLB     0x00400000      /* Huge TLB Page VM */
 #define VM_NONLINEAR   0x00800000      /* Is non-linear (remap_file_pages) */
 
+/* It makes sense to apply VM_ACCOUNT to this vma. */
+#define VM_MAYACCT(vma) (!!((vma)->vm_flags & VM_HUGETLB))
+
 #ifndef VM_STACK_DEFAULT_FLAGS         /* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
 #endif
index 31520c7698549adf44fd22b96037127524fb085a..143a27ef28a2e85eb4951b7019369cb42b3899af 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -489,9 +489,13 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
        int correct_wcount = 0;
        int error;
        struct rb_node ** rb_link, * rb_parent;
+       int accountable = 1;
        unsigned long charged = 0;
 
        if (file) {
+               if (is_file_hugepages(file))
+                       accountable = 0;
+
                if (!file->f_op || !file->f_op->mmap)
                        return -ENODEV;
 
@@ -608,7 +612,8 @@ munmap_back:
            > current->rlim[RLIMIT_AS].rlim_cur)
                return -ENOMEM;
 
-       if (!(flags & MAP_NORESERVE) || sysctl_overcommit_memory > 1) {
+       if (accountable && (!(flags & MAP_NORESERVE) ||
+                       sysctl_overcommit_memory > 1)) {
                if (vm_flags & VM_SHARED) {
                        /* Check memory availability in shmem_file_setup? */
                        vm_flags |= VM_ACCOUNT;
index 24b3d13b51ec30af2326dae082ee52c78e75df70..6c5c8668105601649fa9b865c698adcdb95baeab 100644 (file)
@@ -173,7 +173,8 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
         * a MAP_NORESERVE private mapping to writable will now reserve.
         */
        if (newflags & VM_WRITE) {
-               if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) {
+               if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))
+                               && VM_MAYACCT(vma)) {
                        charged = (end - start) >> PAGE_SHIFT;
                        if (security_vm_enough_memory(charged))
                                return -ENOMEM;
index 574858fa0d2d1815bba0c8ef19b57c55a114c63f..e902b60ecc3005763d33b354ed6b4310f3c002a6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/netlink.h>
 #include <linux/ptrace.h>
 #include <linux/xattr.h>
+#include <linux/hugetlb.h>
 
 int cap_capable (struct task_struct *tsk, int cap)
 {
@@ -358,7 +359,8 @@ int cap_vm_enough_memory(long pages)
                return -ENOMEM;
        }
 
-       allowed = totalram_pages * sysctl_overcommit_ratio / 100;
+       allowed = (totalram_pages - hugetlb_total_pages())
+               * sysctl_overcommit_ratio / 100;
        allowed += total_swap_pages;
 
        if (atomic_read(&vm_committed_space) < allowed)
index 23cb2805afb454bd37e261742872dfc23e0cb105..3bf46b0f5997670118f4ccaf3be0b22a5eea9d1b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/netlink.h>
 #include <net/sock.h>
 #include <linux/xattr.h>
+#include <linux/hugetlb.h>
 
 static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
 {
@@ -146,7 +147,8 @@ static int dummy_vm_enough_memory(long pages)
                return -ENOMEM;
        }
 
-       allowed = totalram_pages * sysctl_overcommit_ratio / 100;
+       allowed = (totalram_pages - hugetlb_total_pages())
+               * sysctl_overcommit_ratio / 100;
        allowed += total_swap_pages;
 
        if (atomic_read(&vm_committed_space) < allowed)
index 0c72dd49215f1c37d634057e010fdea7f16ecf85..4174931f78988a5f69e5adca5e601ce55f14dc25 100644 (file)
@@ -59,6 +59,7 @@
 #include <net/af_unix.h>       /* for Unix socket types */
 #include <linux/parser.h>
 #include <linux/nfs_mount.h>
+#include <linux/hugetlb.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -1544,7 +1545,8 @@ static int selinux_vm_enough_memory(long pages)
                return -ENOMEM;
        }
 
-       allowed = totalram_pages * sysctl_overcommit_ratio / 100;
+       allowed = (totalram_pages - hugetlb_total_pages())
+               * sysctl_overcommit_ratio / 100;
        allowed += total_swap_pages;
 
        if (atomic_read(&vm_committed_space) < allowed)