aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2017-04-20 08:43:51 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-04-25 01:47:32 -0400
commitee71d16d22bb268c1f6a64ef6d3654ace5f1e8c7 (patch)
tree8e8ecc1da0ba8947a9b024a435262460d67caeff
parent5037c22c53603acd4e8c465d750fdd604c600bd3 (diff)
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 <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/mman.h4
-rw-r--r--arch/s390/include/asm/processor.h9
-rw-r--r--arch/s390/kvm/kvm-s390.c4
-rw-r--r--arch/s390/mm/gmap.c2
-rw-r--r--arch/s390/mm/gup.c2
-rw-r--r--arch/s390/mm/mmap.c31
-rw-r--r--arch/s390/mm/pgalloc.c2
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 @@
8 8
9#include <uapi/asm/mman.h> 9#include <uapi/asm/mman.h>
10 10
11#ifndef __ASSEMBLY__
12int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags);
13#define arch_mmap_check(addr, len, flags) s390_mmap_check(addr, len, flags)
14#endif
15#endif /* __S390_MMAN_H__ */ 11#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);
91 * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. 91 * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
92 */ 92 */
93 93
94#define TASK_SIZE_OF(tsk) ((tsk)->mm ? \ 94#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_31BIT) ? \
95 (tsk)->mm->context.asce_limit : TASK_MAX_SIZE) 95 (1UL << 31) : (1UL << 53))
96#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ 96#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \
97 (1UL << 30) : (1UL << 41)) 97 (1UL << 30) : (1UL << 41))
98#define TASK_SIZE TASK_SIZE_OF(current) 98#define TASK_SIZE TASK_SIZE_OF(current)
99#define TASK_MAX_SIZE (1UL << 53) 99#define TASK_SIZE_MAX (1UL << 53)
100 100
101#define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:42)) 101#define STACK_TOP (test_thread_flag(TIF_31BIT) ? \
102 (1UL << 31) : (1UL << 42))
102#define STACK_TOP_MAX (1UL << 42) 103#define STACK_TOP_MAX (1UL << 42)
103 104
104#define HAVE_ARCH_PICK_MMAP_LAYOUT 105#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)
1512 kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT; 1512 kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
1513 } else { 1513 } else {
1514 if (sclp.hamax == U64_MAX) 1514 if (sclp.hamax == U64_MAX)
1515 kvm->arch.mem_limit = TASK_MAX_SIZE; 1515 kvm->arch.mem_limit = TASK_SIZE_MAX;
1516 else 1516 else
1517 kvm->arch.mem_limit = min_t(unsigned long, TASK_MAX_SIZE, 1517 kvm->arch.mem_limit = min_t(unsigned long, TASK_SIZE_MAX,
1518 sclp.hamax + 1); 1518 sclp.hamax + 1);
1519 kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1); 1519 kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1);
1520 if (!kvm->arch.gmap) 1520 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,
431 if ((from | to | len) & (PMD_SIZE - 1)) 431 if ((from | to | len) & (PMD_SIZE - 1))
432 return -EINVAL; 432 return -EINVAL;
433 if (len == 0 || from + len < from || to + len < to || 433 if (len == 0 || from + len < from || to + len < to ||
434 from + len - 1 > TASK_MAX_SIZE || to + len - 1 > gmap->asce_end) 434 from + len - 1 > TASK_SIZE_MAX || to + len - 1 > gmap->asce_end)
435 return -EINVAL; 435 return -EINVAL;
436 436
437 flush = 0; 437 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,
211 addr = start; 211 addr = start;
212 len = (unsigned long) nr_pages << PAGE_SHIFT; 212 len = (unsigned long) nr_pages << PAGE_SHIFT;
213 end = start + len; 213 end = start + len;
214 if ((end <= start) || (end > TASK_SIZE)) 214 if ((end <= start) || (end > mm->context.asce_limit))
215 return 0; 215 return 0;
216 /* 216 /*
217 * local_irq_save() doesn't prevent pagetable teardown, but does 217 * 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,
90 struct vm_area_struct *vma; 90 struct vm_area_struct *vma;
91 struct vm_unmapped_area_info info; 91 struct vm_unmapped_area_info info;
92 92
93 if (len > TASK_SIZE - mmap_min_addr) 93 if (len > mm->context.asce_limit - mmap_min_addr)
94 return -ENOMEM; 94 return -ENOMEM;
95 95
96 if (flags & MAP_FIXED) 96 if (flags & MAP_FIXED)
@@ -99,7 +99,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
99 if (addr) { 99 if (addr) {
100 addr = PAGE_ALIGN(addr); 100 addr = PAGE_ALIGN(addr);
101 vma = find_vma(mm, addr); 101 vma = find_vma(mm, addr);
102 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && 102 if (mm->context.asce_limit - len >= addr &&
103 addr >= mmap_min_addr &&
103 (!vma || addr + len <= vma->vm_start)) 104 (!vma || addr + len <= vma->vm_start))
104 return addr; 105 return addr;
105 } 106 }
@@ -107,7 +108,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
107 info.flags = 0; 108 info.flags = 0;
108 info.length = len; 109 info.length = len;
109 info.low_limit = mm->mmap_base; 110 info.low_limit = mm->mmap_base;
110 info.high_limit = TASK_SIZE; 111 info.high_limit = mm->context.asce_limit;
111 if (filp || (flags & MAP_SHARED)) 112 if (filp || (flags & MAP_SHARED))
112 info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT; 113 info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
113 else 114 else
@@ -127,7 +128,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
127 struct vm_unmapped_area_info info; 128 struct vm_unmapped_area_info info;
128 129
129 /* requested length too big for entire address space */ 130 /* requested length too big for entire address space */
130 if (len > TASK_SIZE - mmap_min_addr) 131 if (len > mm->context.asce_limit - mmap_min_addr)
131 return -ENOMEM; 132 return -ENOMEM;
132 133
133 if (flags & MAP_FIXED) 134 if (flags & MAP_FIXED)
@@ -137,7 +138,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
137 if (addr) { 138 if (addr) {
138 addr = PAGE_ALIGN(addr); 139 addr = PAGE_ALIGN(addr);
139 vma = find_vma(mm, addr); 140 vma = find_vma(mm, addr);
140 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && 141 if (mm->context.asce_limit - len >= addr &&
142 addr >= mmap_min_addr &&
141 (!vma || addr + len <= vma->vm_start)) 143 (!vma || addr + len <= vma->vm_start))
142 return addr; 144 return addr;
143 } 145 }
@@ -163,24 +165,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
163 VM_BUG_ON(addr != -ENOMEM); 165 VM_BUG_ON(addr != -ENOMEM);
164 info.flags = 0; 166 info.flags = 0;
165 info.low_limit = TASK_UNMAPPED_BASE; 167 info.low_limit = TASK_UNMAPPED_BASE;
166 info.high_limit = TASK_SIZE; 168 info.high_limit = mm->context.asce_limit;
167 addr = vm_unmapped_area(&info); 169 addr = vm_unmapped_area(&info);
168 } 170 }
169 171
170 return addr; 172 return addr;
171} 173}
172 174
173int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags)
174{
175 if (is_compat_task() || TASK_SIZE >= TASK_MAX_SIZE)
176 return 0;
177 if (!(flags & MAP_FIXED))
178 addr = 0;
179 if ((addr + len) >= TASK_SIZE)
180 return crst_table_upgrade(current->mm);
181 return 0;
182}
183
184static unsigned long 175static unsigned long
185s390_get_unmapped_area(struct file *filp, unsigned long addr, 176s390_get_unmapped_area(struct file *filp, unsigned long addr,
186 unsigned long len, unsigned long pgoff, unsigned long flags) 177 unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -192,7 +183,8 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr,
192 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); 183 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
193 if (!(area & ~PAGE_MASK)) 184 if (!(area & ~PAGE_MASK))
194 return area; 185 return area;
195 if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < TASK_MAX_SIZE) { 186 if (area == -ENOMEM && !is_compat_task() &&
187 current->mm->context.asce_limit < TASK_SIZE_MAX) {
196 /* Upgrade the page table to 4 levels and retry. */ 188 /* Upgrade the page table to 4 levels and retry. */
197 rc = crst_table_upgrade(mm); 189 rc = crst_table_upgrade(mm);
198 if (rc) 190 if (rc)
@@ -214,7 +206,8 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
214 area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); 206 area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
215 if (!(area & ~PAGE_MASK)) 207 if (!(area & ~PAGE_MASK))
216 return area; 208 return area;
217 if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < TASK_MAX_SIZE) { 209 if (area == -ENOMEM && !is_compat_task() &&
210 current->mm->context.asce_limit < TASK_SIZE_MAX) {
218 /* Upgrade the page table to 4 levels and retry. */ 211 /* Upgrade the page table to 4 levels and retry. */
219 rc = crst_table_upgrade(mm); 212 rc = crst_table_upgrade(mm);
220 if (rc) 213 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)
95 mm->context.asce_limit = 1UL << 53; 95 mm->context.asce_limit = 1UL << 53;
96 mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | 96 mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
97 _ASCE_USER_BITS | _ASCE_TYPE_REGION2; 97 _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
98 mm->task_size = mm->context.asce_limit;
99 spin_unlock_bh(&mm->page_table_lock); 98 spin_unlock_bh(&mm->page_table_lock);
100 99
101 on_each_cpu(__crst_table_upgrade, mm, 0); 100 on_each_cpu(__crst_table_upgrade, mm, 0);
@@ -119,7 +118,6 @@ void crst_table_downgrade(struct mm_struct *mm)
119 mm->context.asce_limit = 1UL << 31; 118 mm->context.asce_limit = 1UL << 31;
120 mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH | 119 mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
121 _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; 120 _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
122 mm->task_size = mm->context.asce_limit;
123 crst_table_free(mm, (unsigned long *) pgd); 121 crst_table_free(mm, (unsigned long *) pgd);
124 122
125 if (current->active_mm == mm) 123 if (current->active_mm == mm)