diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2005-11-23 22:16:15 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 22:50:28 -0500 |
commit | 456752f7505ef8f580ffd157558e661da2767d99 (patch) | |
tree | 8854e9dd2d21ac440f691dd16881e596db61896b /arch/powerpc/mm/hugetlbpage.c | |
parent | 706e6b2caf285d3eb056c2847b7c53ae823e8a87 (diff) |
[PATCH] powerpc: Make hugepage mappings respect hint addresses
Currently, the powerpc version of hugetlb_get_unmapped_area() entirely
ignores the hint address. The only way to get a hugepage mapping at a
specified address is with MAP_FIXED, in which case there's no way
(short of parsing /proc/self/maps) for userspace to tell if it will
clobber an existing mapping. This is inconvenient, so the patch below
makes hugepage mappings use the given hint address if possible.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/mm/hugetlbpage.c')
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 54131b877da3..f6fe3eaf87a3 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; |
@@ -609,6 +620,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
609 | { | 620 | { |
610 | int lastshift; | 621 | int lastshift; |
611 | u16 areamask, curareas; | 622 | u16 areamask, curareas; |
623 | struct vm_area_struct *vma; | ||
612 | 624 | ||
613 | if (HPAGE_SHIFT == 0) | 625 | if (HPAGE_SHIFT == 0) |
614 | return -EINVAL; | 626 | return -EINVAL; |
@@ -618,15 +630,28 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
618 | if (!cpu_has_feature(CPU_FTR_16M_PAGE)) | 630 | if (!cpu_has_feature(CPU_FTR_16M_PAGE)) |
619 | return -EINVAL; | 631 | return -EINVAL; |
620 | 632 | ||
633 | /* Paranoia, caller should have dealt with this */ | ||
634 | BUG_ON((addr + len) < addr); | ||
635 | |||
621 | if (test_thread_flag(TIF_32BIT)) { | 636 | if (test_thread_flag(TIF_32BIT)) { |
637 | /* Paranoia, caller should have dealt with this */ | ||
638 | BUG_ON((addr + len) > 0x100000000UL); | ||
639 | |||
622 | curareas = current->mm->context.low_htlb_areas; | 640 | curareas = current->mm->context.low_htlb_areas; |
623 | 641 | ||
624 | /* First see if we can do the mapping in the existing | 642 | /* First see if we can use the hint address */ |
625 | * low areas */ | 643 | if (addr && (htlb_check_hinted_area(addr, len) == 0)) { |
644 | areamask = LOW_ESID_MASK(addr, len); | ||
645 | if (open_low_hpage_areas(current->mm, areamask) == 0) | ||
646 | return addr; | ||
647 | } | ||
648 | |||
649 | /* Next see if we can map in the existing low areas */ | ||
626 | addr = htlb_get_low_area(len, curareas); | 650 | addr = htlb_get_low_area(len, curareas); |
627 | if (addr != -ENOMEM) | 651 | if (addr != -ENOMEM) |
628 | return addr; | 652 | return addr; |
629 | 653 | ||
654 | /* Finally go looking for areas to open */ | ||
630 | lastshift = 0; | 655 | lastshift = 0; |
631 | for (areamask = LOW_ESID_MASK(0x100000000UL-len, len); | 656 | for (areamask = LOW_ESID_MASK(0x100000000UL-len, len); |
632 | ! lastshift; areamask >>=1) { | 657 | ! lastshift; areamask >>=1) { |
@@ -641,12 +666,22 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
641 | } else { | 666 | } else { |
642 | curareas = current->mm->context.high_htlb_areas; | 667 | curareas = current->mm->context.high_htlb_areas; |
643 | 668 | ||
644 | /* First see if we can do the mapping in the existing | 669 | /* First see if we can use the hint address */ |
645 | * high areas */ | 670 | /* We discourage 64-bit processes from doing hugepage |
671 | * mappings below 4GB (must use MAP_FIXED) */ | ||
672 | if ((addr >= 0x100000000UL) | ||
673 | && (htlb_check_hinted_area(addr, len) == 0)) { | ||
674 | areamask = HTLB_AREA_MASK(addr, len); | ||
675 | if (open_high_hpage_areas(current->mm, areamask) == 0) | ||
676 | return addr; | ||
677 | } | ||
678 | |||
679 | /* Next see if we can map in the existing high areas */ | ||
646 | addr = htlb_get_high_area(len, curareas); | 680 | addr = htlb_get_high_area(len, curareas); |
647 | if (addr != -ENOMEM) | 681 | if (addr != -ENOMEM) |
648 | return addr; | 682 | return addr; |
649 | 683 | ||
684 | /* Finally go looking for areas to open */ | ||
650 | lastshift = 0; | 685 | lastshift = 0; |
651 | for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len); | 686 | for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len); |
652 | ! lastshift; areamask >>=1) { | 687 | ! lastshift; areamask >>=1) { |