Commit ee71d16d authored by Martin Schwidefsky's avatar Martin Schwidefsky

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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 5037c22c
...@@ -8,8 +8,4 @@ ...@@ -8,8 +8,4 @@
#include <uapi/asm/mman.h> #include <uapi/asm/mman.h>
#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__ */ #endif /* __S390_MMAN_H__ */
...@@ -91,14 +91,15 @@ extern void execve_tail(void); ...@@ -91,14 +91,15 @@ extern void execve_tail(void);
* User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
*/ */
#define TASK_SIZE_OF(tsk) ((tsk)->mm ? \ #define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_31BIT) ? \
(tsk)->mm->context.asce_limit : TASK_MAX_SIZE) (1UL << 31) : (1UL << 53))
#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \
(1UL << 30) : (1UL << 41)) (1UL << 30) : (1UL << 41))
#define TASK_SIZE TASK_SIZE_OF(current) #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 STACK_TOP_MAX (1UL << 42)
#define HAVE_ARCH_PICK_MMAP_LAYOUT #define HAVE_ARCH_PICK_MMAP_LAYOUT
......
...@@ -1512,9 +1512,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -1512,9 +1512,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT; kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
} else { } else {
if (sclp.hamax == U64_MAX) if (sclp.hamax == U64_MAX)
kvm->arch.mem_limit = TASK_MAX_SIZE; kvm->arch.mem_limit = TASK_SIZE_MAX;
else 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); sclp.hamax + 1);
kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1); kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1);
if (!kvm->arch.gmap) if (!kvm->arch.gmap)
......
...@@ -431,7 +431,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from, ...@@ -431,7 +431,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
if ((from | to | len) & (PMD_SIZE - 1)) if ((from | to | len) & (PMD_SIZE - 1))
return -EINVAL; return -EINVAL;
if (len == 0 || from + len < from || to + len < to || 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; return -EINVAL;
flush = 0; flush = 0;
......
...@@ -211,7 +211,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write, ...@@ -211,7 +211,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
addr = start; addr = start;
len = (unsigned long) nr_pages << PAGE_SHIFT; len = (unsigned long) nr_pages << PAGE_SHIFT;
end = start + len; end = start + len;
if ((end <= start) || (end > TASK_SIZE)) if ((end <= start) || (end > mm->context.asce_limit))
return 0; return 0;
/* /*
* local_irq_save() doesn't prevent pagetable teardown, but does * local_irq_save() doesn't prevent pagetable teardown, but does
......
...@@ -90,7 +90,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, ...@@ -90,7 +90,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct vm_unmapped_area_info info; struct vm_unmapped_area_info info;
if (len > TASK_SIZE - mmap_min_addr) if (len > mm->context.asce_limit - mmap_min_addr)
return -ENOMEM; return -ENOMEM;
if (flags & MAP_FIXED) if (flags & MAP_FIXED)
...@@ -99,7 +99,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, ...@@ -99,7 +99,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (addr) { if (addr) {
addr = PAGE_ALIGN(addr); addr = PAGE_ALIGN(addr);
vma = find_vma(mm, 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)) (!vma || addr + len <= vma->vm_start))
return addr; return addr;
} }
...@@ -107,7 +108,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, ...@@ -107,7 +108,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
info.flags = 0; info.flags = 0;
info.length = len; info.length = len;
info.low_limit = mm->mmap_base; info.low_limit = mm->mmap_base;
info.high_limit = TASK_SIZE; info.high_limit = mm->context.asce_limit;
if (filp || (flags & MAP_SHARED)) if (filp || (flags & MAP_SHARED))
info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT; info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
else else
...@@ -127,7 +128,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, ...@@ -127,7 +128,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
struct vm_unmapped_area_info info; struct vm_unmapped_area_info info;
/* requested length too big for entire address space */ /* 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; return -ENOMEM;
if (flags & MAP_FIXED) if (flags & MAP_FIXED)
...@@ -137,7 +138,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, ...@@ -137,7 +138,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
if (addr) { if (addr) {
addr = PAGE_ALIGN(addr); addr = PAGE_ALIGN(addr);
vma = find_vma(mm, 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)) (!vma || addr + len <= vma->vm_start))
return addr; return addr;
} }
...@@ -163,24 +165,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, ...@@ -163,24 +165,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
VM_BUG_ON(addr != -ENOMEM); VM_BUG_ON(addr != -ENOMEM);
info.flags = 0; info.flags = 0;
info.low_limit = TASK_UNMAPPED_BASE; info.low_limit = TASK_UNMAPPED_BASE;
info.high_limit = TASK_SIZE; info.high_limit = mm->context.asce_limit;
addr = vm_unmapped_area(&info); addr = vm_unmapped_area(&info);
} }
return addr; 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 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)
...@@ -192,7 +183,8 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr, ...@@ -192,7 +183,8 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr,
area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
if (!(area & ~PAGE_MASK)) if (!(area & ~PAGE_MASK))
return area; 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. */ /* Upgrade the page table to 4 levels and retry. */
rc = crst_table_upgrade(mm); rc = crst_table_upgrade(mm);
if (rc) if (rc)
...@@ -214,7 +206,8 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, ...@@ -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); area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
if (!(area & ~PAGE_MASK)) if (!(area & ~PAGE_MASK))
return area; 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. */ /* Upgrade the page table to 4 levels and retry. */
rc = crst_table_upgrade(mm); rc = crst_table_upgrade(mm);
if (rc) if (rc)
......
...@@ -95,7 +95,6 @@ int crst_table_upgrade(struct mm_struct *mm) ...@@ -95,7 +95,6 @@ int crst_table_upgrade(struct mm_struct *mm)
mm->context.asce_limit = 1UL << 53; mm->context.asce_limit = 1UL << 53;
mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
_ASCE_USER_BITS | _ASCE_TYPE_REGION2; _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
mm->task_size = mm->context.asce_limit;
spin_unlock_bh(&mm->page_table_lock); spin_unlock_bh(&mm->page_table_lock);
on_each_cpu(__crst_table_upgrade, mm, 0); on_each_cpu(__crst_table_upgrade, mm, 0);
...@@ -119,7 +118,6 @@ void crst_table_downgrade(struct mm_struct *mm) ...@@ -119,7 +118,6 @@ void crst_table_downgrade(struct mm_struct *mm)
mm->context.asce_limit = 1UL << 31; mm->context.asce_limit = 1UL << 31;
mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
_ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
mm->task_size = mm->context.asce_limit;
crst_table_free(mm, (unsigned long *) pgd); crst_table_free(mm, (unsigned long *) pgd);
if (current->active_mm == mm) if (current->active_mm == mm)
......
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