From ee71d16d22bb268c1f6a64ef6d3654ace5f1e8c7 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 20 Apr 2017 14:43:51 +0200 Subject: [PATCH] s390/mm: make TASK_SIZE independent from the number of page table levels The TASK_SIZE for a process should be maximum possible size of the address space, 2GB for a 31-bit process and 8PB for a 64-bit process. The number of page table levels required for a given memory layout is a consequence of the mapped memory areas and their location. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/mman.h | 4 ---- arch/s390/include/asm/processor.h | 9 +++++---- arch/s390/kvm/kvm-s390.c | 4 ++-- arch/s390/mm/gmap.c | 2 +- arch/s390/mm/gup.c | 2 +- arch/s390/mm/mmap.c | 31 ++++++++++++------------------- arch/s390/mm/pgalloc.c | 2 -- 7 files changed, 21 insertions(+), 33 deletions(-) diff --git a/arch/s390/include/asm/mman.h b/arch/s390/include/asm/mman.h index b55a59e1d134..b79813d9cf68 100644 --- a/arch/s390/include/asm/mman.h +++ b/arch/s390/include/asm/mman.h @@ -8,8 +8,4 @@ #include -#ifndef __ASSEMBLY__ -int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags); -#define arch_mmap_check(addr, len, flags) s390_mmap_check(addr, len, flags) -#endif #endif /* __S390_MMAN_H__ */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index cc101f9371cb..60d395fdc864 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -91,14 +91,15 @@ extern void execve_tail(void); * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. */ -#define TASK_SIZE_OF(tsk) ((tsk)->mm ? \ - (tsk)->mm->context.asce_limit : TASK_MAX_SIZE) +#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_31BIT) ? \ + (1UL << 31) : (1UL << 53)) #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ (1UL << 30) : (1UL << 41)) #define TASK_SIZE TASK_SIZE_OF(current) -#define TASK_MAX_SIZE (1UL << 53) +#define TASK_SIZE_MAX (1UL << 53) -#define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:42)) +#define STACK_TOP (test_thread_flag(TIF_31BIT) ? \ + (1UL << 31) : (1UL << 42)) #define STACK_TOP_MAX (1UL << 42) #define HAVE_ARCH_PICK_MMAP_LAYOUT diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index fd6cd05bb6a7..28983836c0f7 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1512,9 +1512,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT; } else { if (sclp.hamax == U64_MAX) - kvm->arch.mem_limit = TASK_MAX_SIZE; + kvm->arch.mem_limit = TASK_SIZE_MAX; else - kvm->arch.mem_limit = min_t(unsigned long, TASK_MAX_SIZE, + kvm->arch.mem_limit = min_t(unsigned long, TASK_SIZE_MAX, sclp.hamax + 1); kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1); if (!kvm->arch.gmap) diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index ffb55c935eda..7f6db1e6c048 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -431,7 +431,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from, if ((from | to | len) & (PMD_SIZE - 1)) return -EINVAL; if (len == 0 || from + len < from || to + len < to || - from + len - 1 > TASK_MAX_SIZE || to + len - 1 > gmap->asce_end) + from + len - 1 > TASK_SIZE_MAX || to + len - 1 > gmap->asce_end) return -EINVAL; flush = 0; diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 18d4107e10ee..b7b779c40a5b 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -211,7 +211,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write, addr = start; len = (unsigned long) nr_pages << PAGE_SHIFT; end = start + len; - if ((end <= start) || (end > TASK_SIZE)) + if ((end <= start) || (end > mm->context.asce_limit)) return 0; /* * local_irq_save() doesn't prevent pagetable teardown, but does diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 50618614881f..eed233ce59dd 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -90,7 +90,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, struct vm_area_struct *vma; struct vm_unmapped_area_info info; - if (len > TASK_SIZE - mmap_min_addr) + if (len > mm->context.asce_limit - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -99,7 +99,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && + if (mm->context.asce_limit - len >= addr && + addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } @@ -107,7 +108,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, info.flags = 0; info.length = len; info.low_limit = mm->mmap_base; - info.high_limit = TASK_SIZE; + info.high_limit = mm->context.asce_limit; if (filp || (flags & MAP_SHARED)) info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT; else @@ -127,7 +128,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct vm_unmapped_area_info info; /* requested length too big for entire address space */ - if (len > TASK_SIZE - mmap_min_addr) + if (len > mm->context.asce_limit - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -137,7 +138,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && + if (mm->context.asce_limit - len >= addr && + addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } @@ -163,24 +165,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, VM_BUG_ON(addr != -ENOMEM); info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = TASK_SIZE; + info.high_limit = mm->context.asce_limit; addr = vm_unmapped_area(&info); } return addr; } -int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) -{ - if (is_compat_task() || TASK_SIZE >= TASK_MAX_SIZE) - return 0; - if (!(flags & MAP_FIXED)) - addr = 0; - if ((addr + len) >= TASK_SIZE) - return crst_table_upgrade(current->mm); - return 0; -} - static unsigned long s390_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) @@ -192,7 +183,8 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr, area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); if (!(area & ~PAGE_MASK)) return area; - if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < TASK_MAX_SIZE) { + if (area == -ENOMEM && !is_compat_task() && + current->mm->context.asce_limit < TASK_SIZE_MAX) { /* Upgrade the page table to 4 levels and retry. */ rc = crst_table_upgrade(mm); if (rc) @@ -214,7 +206,8 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); if (!(area & ~PAGE_MASK)) return area; - if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < TASK_MAX_SIZE) { + if (area == -ENOMEM && !is_compat_task() && + current->mm->context.asce_limit < TASK_SIZE_MAX) { /* Upgrade the page table to 4 levels and retry. */ rc = crst_table_upgrade(mm); if (rc) diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index 2776bad61094..f502cbe657af 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -95,7 +95,6 @@ int crst_table_upgrade(struct mm_struct *mm) mm->context.asce_limit = 1UL << 53; mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | _ASCE_USER_BITS | _ASCE_TYPE_REGION2; - mm->task_size = mm->context.asce_limit; spin_unlock_bh(&mm->page_table_lock); on_each_cpu(__crst_table_upgrade, mm, 0); @@ -119,7 +118,6 @@ void crst_table_downgrade(struct mm_struct *mm) mm->context.asce_limit = 1UL << 31; mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; - mm->task_size = mm->context.asce_limit; crst_table_free(mm, (unsigned long *) pgd); if (current->active_mm == mm) -- 2.39.2