Commit 2e9b367c2273ed21c9852a04d90944d472c4f3e6
Committed by
Linus Torvalds
1 parent
4c88726597
Exists in
master
and in
4 other branches
[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) |