diff options
Diffstat (limited to 'arch/powerpc/mm/hugetlbpage.c')
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 54131b877da..b51bb28c054 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c | |||
@@ -549,6 +549,17 @@ fail: | |||
549 | return addr; | 549 | return addr; |
550 | } | 550 | } |
551 | 551 | ||
552 | static int htlb_check_hinted_area(unsigned long addr, unsigned long len) | ||
553 | { | ||
554 | struct vm_area_struct *vma; | ||
555 | |||
556 | vma = find_vma(current->mm, addr); | ||
557 | if (!vma || ((addr + len) <= vma->vm_start)) | ||
558 | return 0; | ||
559 | |||
560 | return -ENOMEM; | ||
561 | } | ||
562 | |||
552 | static unsigned long htlb_get_low_area(unsigned long len, u16 segmask) | 563 | static unsigned long htlb_get_low_area(unsigned long len, u16 segmask) |
553 | { | 564 | { |
554 | unsigned long addr = 0; | 565 | unsigned long addr = 0; |
@@ -618,15 +629,28 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
618 | if (!cpu_has_feature(CPU_FTR_16M_PAGE)) | 629 | if (!cpu_has_feature(CPU_FTR_16M_PAGE)) |
619 | return -EINVAL; | 630 | return -EINVAL; |
620 | 631 | ||
632 | /* Paranoia, caller should have dealt with this */ | ||
633 | BUG_ON((addr + len) < addr); | ||
634 | |||
621 | if (test_thread_flag(TIF_32BIT)) { | 635 | if (test_thread_flag(TIF_32BIT)) { |
636 | /* Paranoia, caller should have dealt with this */ | ||
637 | BUG_ON((addr + len) > 0x100000000UL); | ||
638 | |||
622 | curareas = current->mm->context.low_htlb_areas; | 639 | curareas = current->mm->context.low_htlb_areas; |
623 | 640 | ||
624 | /* First see if we can do the mapping in the existing | 641 | /* First see if we can use the hint address */ |
625 | * low areas */ | 642 | if (addr && (htlb_check_hinted_area(addr, len) == 0)) { |
643 | areamask = LOW_ESID_MASK(addr, len); | ||
644 | if (open_low_hpage_areas(current->mm, areamask) == 0) | ||
645 | return addr; | ||
646 | } | ||
647 | |||
648 | /* Next see if we can map in the existing low areas */ | ||
626 | addr = htlb_get_low_area(len, curareas); | 649 | addr = htlb_get_low_area(len, curareas); |
627 | if (addr != -ENOMEM) | 650 | if (addr != -ENOMEM) |
628 | return addr; | 651 | return addr; |
629 | 652 | ||
653 | /* Finally go looking for areas to open */ | ||
630 | lastshift = 0; | 654 | lastshift = 0; |
631 | for (areamask = LOW_ESID_MASK(0x100000000UL-len, len); | 655 | for (areamask = LOW_ESID_MASK(0x100000000UL-len, len); |
632 | ! lastshift; areamask >>=1) { | 656 | ! lastshift; areamask >>=1) { |
@@ -641,12 +665,22 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
641 | } else { | 665 | } else { |
642 | curareas = current->mm->context.high_htlb_areas; | 666 | curareas = current->mm->context.high_htlb_areas; |
643 | 667 | ||
644 | /* First see if we can do the mapping in the existing | 668 | /* First see if we can use the hint address */ |
645 | * high areas */ | 669 | /* We discourage 64-bit processes from doing hugepage |
670 | * mappings below 4GB (must use MAP_FIXED) */ | ||
671 | if ((addr >= 0x100000000UL) | ||
672 | && (htlb_check_hinted_area(addr, len) == 0)) { | ||
673 | areamask = HTLB_AREA_MASK(addr, len); | ||
674 | if (open_high_hpage_areas(current->mm, areamask) == 0) | ||
675 | return addr; | ||
676 | } | ||
677 | |||
678 | /* Next see if we can map in the existing high areas */ | ||
646 | addr = htlb_get_high_area(len, curareas); | 679 | addr = htlb_get_high_area(len, curareas); |
647 | if (addr != -ENOMEM) | 680 | if (addr != -ENOMEM) |
648 | return addr; | 681 | return addr; |
649 | 682 | ||
683 | /* Finally go looking for areas to open */ | ||
650 | lastshift = 0; | 684 | lastshift = 0; |
651 | for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len); | 685 | for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len); |
652 | ! lastshift; areamask >>=1) { | 686 | ! lastshift; areamask >>=1) { |