powerpc: Make hugepage mappings resepect hint addresses

David Gibson david at gibson.dropbear.id.au
Thu Nov 24 14:16:15 EST 2005


Andrew, please apply.

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 at gibson.dropbear.id.au>

Index: working-2.6/arch/powerpc/mm/hugetlbpage.c
===================================================================
--- working-2.6.orig/arch/powerpc/mm/hugetlbpage.c	2005-11-24 13:38:12.000000000 +1100
+++ working-2.6/arch/powerpc/mm/hugetlbpage.c	2005-11-24 14:09:42.000000000 +1100
@@ -524,6 +524,17 @@ fail:
 	return addr;
 }
 
+static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
+{
+	struct vm_area_struct *vma;
+
+	vma = find_vma(current->mm, addr);
+	if (!vma || ((addr + len) <= vma->vm_start))
+		return 0;
+
+	return -ENOMEM;
+}
+
 static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
 {
 	unsigned long addr = 0;
@@ -584,6 +595,7 @@ unsigned long hugetlb_get_unmapped_area(
 {
 	int lastshift;
 	u16 areamask, curareas;
+	struct vm_area_struct *vma;
 
 	if (HPAGE_SHIFT == 0)
 		return -EINVAL;
@@ -593,15 +605,28 @@ unsigned long hugetlb_get_unmapped_area(
 	if (!cpu_has_feature(CPU_FTR_16M_PAGE))
 		return -EINVAL;
 
+	/* Paranoia, caller should have dealt with this */
+	BUG_ON((addr + len)  < addr);
+
 	if (test_thread_flag(TIF_32BIT)) {
+		/* Paranoia, caller should have dealt with this */
+		BUG_ON((addr + len) > 0x100000000UL);
+
 		curareas = current->mm->context.low_htlb_areas;
 
-		/* First see if we can do the mapping in the existing
-		 * low areas */
+		/* First see if we can use the hint address */
+		if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
+			areamask = LOW_ESID_MASK(addr, len);
+			if (open_low_hpage_areas(current->mm, areamask) == 0)
+				return addr;
+		}
+
+		/* Next see if we can map in the existing low areas */
 		addr = htlb_get_low_area(len, curareas);
 		if (addr != -ENOMEM)
 			return addr;
 
+		/* Finally go looking for areas to open */
 		lastshift = 0;
 		for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
 		     ! lastshift; areamask >>=1) {
@@ -616,12 +641,22 @@ unsigned long hugetlb_get_unmapped_area(
 	} else {
 		curareas = current->mm->context.high_htlb_areas;
 
-		/* First see if we can do the mapping in the existing
-		 * high areas */
+		/* First see if we can use the hint address */
+		/* We discourage 64-bit processes from doing hugepage
+		 * mappings below 4GB (must use MAP_FIXED) */
+		if ((addr >= 0x100000000UL)
+		    && (htlb_check_hinted_area(addr, len) == 0)) {
+			areamask = HTLB_AREA_MASK(addr, len);
+			if (open_high_hpage_areas(current->mm, areamask) == 0)
+				return addr;
+		}
+
+		/* Next see if we can map in the existing high areas */
 		addr = htlb_get_high_area(len, curareas);
 		if (addr != -ENOMEM)
 			return addr;
 
+		/* Finally go looking for areas to open */
 		lastshift = 0;
 		for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
 		     ! lastshift; areamask >>=1) {

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson



More information about the Linuxppc64-dev mailing list