aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/mmap.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index 43c4955535aa..da3e9c04bf37 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -6,6 +6,7 @@
6 * Address space accounting code <alan@lxorguk.ukuu.org.uk> 6 * Address space accounting code <alan@lxorguk.ukuu.org.uk>
7 */ 7 */
8 8
9#include <linux/kernel.h>
9#include <linux/slab.h> 10#include <linux/slab.h>
10#include <linux/backing-dev.h> 11#include <linux/backing-dev.h>
11#include <linux/mm.h> 12#include <linux/mm.h>
@@ -550,6 +551,34 @@ static int find_vma_links(struct mm_struct *mm, unsigned long addr,
550 return 0; 551 return 0;
551} 552}
552 553
554static unsigned long count_vma_pages_range(struct mm_struct *mm,
555 unsigned long addr, unsigned long end)
556{
557 unsigned long nr_pages = 0;
558 struct vm_area_struct *vma;
559
560 /* Find first overlaping mapping */
561 vma = find_vma_intersection(mm, addr, end);
562 if (!vma)
563 return 0;
564
565 nr_pages = (min(end, vma->vm_end) -
566 max(addr, vma->vm_start)) >> PAGE_SHIFT;
567
568 /* Iterate over the rest of the overlaps */
569 for (vma = vma->vm_next; vma; vma = vma->vm_next) {
570 unsigned long overlap_len;
571
572 if (vma->vm_start > end)
573 break;
574
575 overlap_len = min(end, vma->vm_end) - vma->vm_start;
576 nr_pages += overlap_len >> PAGE_SHIFT;
577 }
578
579 return nr_pages;
580}
581
553void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, 582void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
554 struct rb_node **rb_link, struct rb_node *rb_parent) 583 struct rb_node **rb_link, struct rb_node *rb_parent)
555{ 584{
@@ -1442,6 +1471,23 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
1442 unsigned long charged = 0; 1471 unsigned long charged = 0;
1443 struct inode *inode = file ? file_inode(file) : NULL; 1472 struct inode *inode = file ? file_inode(file) : NULL;
1444 1473
1474 /* Check against address space limit. */
1475 if (!may_expand_vm(mm, len >> PAGE_SHIFT)) {
1476 unsigned long nr_pages;
1477
1478 /*
1479 * MAP_FIXED may remove pages of mappings that intersects with
1480 * requested mapping. Account for the pages it would unmap.
1481 */
1482 if (!(vm_flags & MAP_FIXED))
1483 return -ENOMEM;
1484
1485 nr_pages = count_vma_pages_range(mm, addr, addr + len);
1486
1487 if (!may_expand_vm(mm, (len >> PAGE_SHIFT) - nr_pages))
1488 return -ENOMEM;
1489 }
1490
1445 /* Clear old maps */ 1491 /* Clear old maps */
1446 error = -ENOMEM; 1492 error = -ENOMEM;
1447munmap_back: 1493munmap_back:
@@ -1451,10 +1497,6 @@ munmap_back:
1451 goto munmap_back; 1497 goto munmap_back;
1452 } 1498 }
1453 1499
1454 /* Check against address space limit. */
1455 if (!may_expand_vm(mm, len >> PAGE_SHIFT))
1456 return -ENOMEM;
1457
1458 /* 1500 /*
1459 * Private writable mapping: check memory availability 1501 * Private writable mapping: check memory availability
1460 */ 1502 */