Commit 0fb1d9bc authored by Martin Schwidefsky's avatar Martin Schwidefsky

[S390] make page table upgrade work again

After TASK_SIZE now gives the current size of the address space the
upgrade of a 64 bit process from 3 to 4 levels of page table  needs
to use the arch_mmap_check hook to catch large mmap lengths. The
get_unmapped_area* functions need to check for -ENOMEM from the
arch_get_unmapped_area*, upgrade the page table and retry.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent f481bfaf
...@@ -22,4 +22,9 @@ ...@@ -22,4 +22,9 @@
#define MCL_CURRENT 1 /* lock all current mappings */ #define MCL_CURRENT 1 /* lock all current mappings */
#define MCL_FUTURE 2 /* lock all future mappings */ #define MCL_FUTURE 2 /* lock all future mappings */
#if defined(__KERNEL__) && !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
int s390_mmap_check(unsigned long addr, unsigned long len);
#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len)
#endif
#endif /* __S390_MMAN_H__ */ #endif /* __S390_MMAN_H__ */
...@@ -89,42 +89,58 @@ EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); ...@@ -89,42 +89,58 @@ EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
#else #else
int s390_mmap_check(unsigned long addr, unsigned long len)
{
if (!test_thread_flag(TIF_31BIT) &&
len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
return crst_table_upgrade(current->mm, 1UL << 53);
return 0;
}
static unsigned long static unsigned long
s390_get_unmapped_area(struct file *filp, unsigned long addr, s390_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags) unsigned long len, unsigned long pgoff, unsigned long flags)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
unsigned long area;
int rc; int rc;
addr = arch_get_unmapped_area(filp, addr, len, pgoff, flags); area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
if (addr & ~PAGE_MASK) if (!(area & ~PAGE_MASK))
return addr; return area;
if (unlikely(mm->context.asce_limit < addr + len)) { if (area == -ENOMEM &&
rc = crst_table_upgrade(mm, addr + len); !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
/* Upgrade the page table to 4 levels and retry. */
rc = crst_table_upgrade(mm, 1UL << 53);
if (rc) if (rc)
return (unsigned long) rc; return (unsigned long) rc;
area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
} }
return addr; return area;
} }
static unsigned long static unsigned long
s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
const unsigned long len, const unsigned long pgoff, const unsigned long len, const unsigned long pgoff,
const unsigned long flags) const unsigned long flags)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
unsigned long addr = addr0; unsigned long area;
int rc; int rc;
addr = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
if (addr & ~PAGE_MASK) if (!(area & ~PAGE_MASK))
return addr; return area;
if (unlikely(mm->context.asce_limit < addr + len)) { if (area == -ENOMEM &&
rc = crst_table_upgrade(mm, addr + len); !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
/* Upgrade the page table to 4 levels and retry. */
rc = crst_table_upgrade(mm, 1UL << 53);
if (rc) if (rc)
return (unsigned long) rc; return (unsigned long) rc;
area = arch_get_unmapped_area_topdown(filp, addr, len,
pgoff, flags);
} }
return addr; return area;
} }
/* /*
* This function, called very early during the creation of a new * This function, called very early during the creation of a new
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment