Commit 2e9b367c2273ed21c9852a04d90944d472c4f3e6

Authored by Adam Litke
Committed by Linus Torvalds
1 parent 4c88726597

[PATCH] hugetlb: overcommit accounting check

Basic overcommit checking for hugetlb_file_map() based on an implementation
used with demand faulting in SLES9.

Since demand faulting can't guarantee the availability of pages at mmap
time, this patch implements a basic sanity check to ensure that the number
of huge pages required to satisfy the mmap are currently available.
Despite the obvious race, I think it is a good start on doing proper
accounting.  I'd like to work towards an accounting system that mimics the
semantics of normal pages (especially for the MAP_PRIVATE/COW case).  That
work is underway and builds on what this patch starts.

Huge page shared memory segments are simpler and still maintain their
commit on shmget semantics.

Signed-off-by: Adam Litke <agl@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 1 changed file with 53 additions and 10 deletions Side-by-side Diff

fs/hugetlbfs/inode.c
... ... @@ -45,9 +45,58 @@
45 45  
46 46 int sysctl_hugetlb_shm_group;
47 47  
  48 +static void huge_pagevec_release(struct pagevec *pvec)
  49 +{
  50 + int i;
  51 +
  52 + for (i = 0; i < pagevec_count(pvec); ++i)
  53 + put_page(pvec->pages[i]);
  54 +
  55 + pagevec_reinit(pvec);
  56 +}
  57 +
  58 +/*
  59 + * huge_pages_needed tries to determine the number of new huge pages that
  60 + * will be required to fully populate this VMA. This will be equal to
  61 + * the size of the VMA in huge pages minus the number of huge pages
  62 + * (covered by this VMA) that are found in the page cache.
  63 + *
  64 + * Result is in bytes to be compatible with is_hugepage_mem_enough()
  65 + */
  66 +unsigned long
  67 +huge_pages_needed(struct address_space *mapping, struct vm_area_struct *vma)
  68 +{
  69 + int i;
  70 + struct pagevec pvec;
  71 + unsigned long start = vma->vm_start;
  72 + unsigned long end = vma->vm_end;
  73 + unsigned long hugepages = (end - start) >> HPAGE_SHIFT;
  74 + pgoff_t next = vma->vm_pgoff;
  75 + pgoff_t endpg = next + ((end - start) >> PAGE_SHIFT);
  76 +
  77 + pagevec_init(&pvec, 0);
  78 + while (next < endpg) {
  79 + if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE))
  80 + break;
  81 + for (i = 0; i < pagevec_count(&pvec); i++) {
  82 + struct page *page = pvec.pages[i];
  83 + if (page->index > next)
  84 + next = page->index;
  85 + if (page->index >= endpg)
  86 + break;
  87 + next++;
  88 + hugepages--;
  89 + }
  90 + huge_pagevec_release(&pvec);
  91 + }
  92 + return hugepages << HPAGE_SHIFT;
  93 +}
  94 +
48 95 static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
49 96 {
50 97 struct inode *inode = file->f_dentry->d_inode;
  98 + struct address_space *mapping = inode->i_mapping;
  99 + unsigned long bytes;
51 100 loff_t len, vma_len;
52 101 int ret;
53 102  
... ... @@ -66,6 +115,10 @@
66 115 if (vma->vm_end - vma->vm_start < HPAGE_SIZE)
67 116 return -EINVAL;
68 117  
  118 + bytes = huge_pages_needed(mapping, vma);
  119 + if (!is_hugepage_mem_enough(bytes))
  120 + return -ENOMEM;
  121 +
69 122 vma_len = (loff_t)(vma->vm_end - vma->vm_start);
70 123  
71 124 down(&inode->i_sem);
... ... @@ -166,16 +219,6 @@
166 219 struct page *page, unsigned offset, unsigned to)
167 220 {
168 221 return -EINVAL;
169   -}
170   -
171   -static void huge_pagevec_release(struct pagevec *pvec)
172   -{
173   - int i;
174   -
175   - for (i = 0; i < pagevec_count(pvec); ++i)
176   - put_page(pvec->pages[i]);
177   -
178   - pagevec_reinit(pvec);
179 222 }
180 223  
181 224 static void truncate_huge_page(struct page *page)