[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>
This commit is contained in:
committed by
Paul Mackerras
parent
706e6b2caf
commit
456752f750
@@ -549,6 +549,17 @@ fail:
|
|||||||
return addr;
|
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)
|
static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
|
||||||
{
|
{
|
||||||
unsigned long addr = 0;
|
unsigned long addr = 0;
|
||||||
@@ -609,6 +620,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
|
|||||||
{
|
{
|
||||||
int lastshift;
|
int lastshift;
|
||||||
u16 areamask, curareas;
|
u16 areamask, curareas;
|
||||||
|
struct vm_area_struct *vma;
|
||||||
|
|
||||||
if (HPAGE_SHIFT == 0)
|
if (HPAGE_SHIFT == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -618,15 +630,28 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
|
|||||||
if (!cpu_has_feature(CPU_FTR_16M_PAGE))
|
if (!cpu_has_feature(CPU_FTR_16M_PAGE))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Paranoia, caller should have dealt with this */
|
||||||
|
BUG_ON((addr + len) < addr);
|
||||||
|
|
||||||
if (test_thread_flag(TIF_32BIT)) {
|
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;
|
curareas = current->mm->context.low_htlb_areas;
|
||||||
|
|
||||||
/* First see if we can do the mapping in the existing
|
/* First see if we can use the hint address */
|
||||||
* low areas */
|
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);
|
addr = htlb_get_low_area(len, curareas);
|
||||||
if (addr != -ENOMEM)
|
if (addr != -ENOMEM)
|
||||||
return addr;
|
return addr;
|
||||||
|
|
||||||
|
/* Finally go looking for areas to open */
|
||||||
lastshift = 0;
|
lastshift = 0;
|
||||||
for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
|
for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
|
||||||
! lastshift; areamask >>=1) {
|
! lastshift; areamask >>=1) {
|
||||||
@@ -641,12 +666,22 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
|
|||||||
} else {
|
} else {
|
||||||
curareas = current->mm->context.high_htlb_areas;
|
curareas = current->mm->context.high_htlb_areas;
|
||||||
|
|
||||||
/* First see if we can do the mapping in the existing
|
/* First see if we can use the hint address */
|
||||||
* high areas */
|
/* 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);
|
addr = htlb_get_high_area(len, curareas);
|
||||||
if (addr != -ENOMEM)
|
if (addr != -ENOMEM)
|
||||||
return addr;
|
return addr;
|
||||||
|
|
||||||
|
/* Finally go looking for areas to open */
|
||||||
lastshift = 0;
|
lastshift = 0;
|
||||||
for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
|
for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
|
||||||
! lastshift; areamask >>=1) {
|
! lastshift; areamask >>=1) {
|
||||||
|
Reference in New Issue
Block a user