|
@@ -6,6 +6,7 @@
|
|
|
* Address space accounting code <alan@lxorguk.ukuu.org.uk>
|
|
|
*/
|
|
|
|
|
|
+#include <linux/kernel.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/backing-dev.h>
|
|
|
#include <linux/mm.h>
|
|
@@ -550,6 +551,34 @@ static int find_vma_links(struct mm_struct *mm, unsigned long addr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static unsigned long count_vma_pages_range(struct mm_struct *mm,
|
|
|
+ unsigned long addr, unsigned long end)
|
|
|
+{
|
|
|
+ unsigned long nr_pages = 0;
|
|
|
+ struct vm_area_struct *vma;
|
|
|
+
|
|
|
+ /* Find first overlaping mapping */
|
|
|
+ vma = find_vma_intersection(mm, addr, end);
|
|
|
+ if (!vma)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ nr_pages = (min(end, vma->vm_end) -
|
|
|
+ max(addr, vma->vm_start)) >> PAGE_SHIFT;
|
|
|
+
|
|
|
+ /* Iterate over the rest of the overlaps */
|
|
|
+ for (vma = vma->vm_next; vma; vma = vma->vm_next) {
|
|
|
+ unsigned long overlap_len;
|
|
|
+
|
|
|
+ if (vma->vm_start > end)
|
|
|
+ break;
|
|
|
+
|
|
|
+ overlap_len = min(end, vma->vm_end) - vma->vm_start;
|
|
|
+ nr_pages += overlap_len >> PAGE_SHIFT;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nr_pages;
|
|
|
+}
|
|
|
+
|
|
|
void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
struct rb_node **rb_link, struct rb_node *rb_parent)
|
|
|
{
|
|
@@ -1442,6 +1471,23 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
|
|
unsigned long charged = 0;
|
|
|
struct inode *inode = file ? file_inode(file) : NULL;
|
|
|
|
|
|
+ /* Check against address space limit. */
|
|
|
+ if (!may_expand_vm(mm, len >> PAGE_SHIFT)) {
|
|
|
+ unsigned long nr_pages;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * MAP_FIXED may remove pages of mappings that intersects with
|
|
|
+ * requested mapping. Account for the pages it would unmap.
|
|
|
+ */
|
|
|
+ if (!(vm_flags & MAP_FIXED))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ nr_pages = count_vma_pages_range(mm, addr, addr + len);
|
|
|
+
|
|
|
+ if (!may_expand_vm(mm, (len >> PAGE_SHIFT) - nr_pages))
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
/* Clear old maps */
|
|
|
error = -ENOMEM;
|
|
|
munmap_back:
|
|
@@ -1451,10 +1497,6 @@ munmap_back:
|
|
|
goto munmap_back;
|
|
|
}
|
|
|
|
|
|
- /* Check against address space limit. */
|
|
|
- if (!may_expand_vm(mm, len >> PAGE_SHIFT))
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
/*
|
|
|
* Private writable mapping: check memory availability
|
|
|
*/
|