diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2017-04-20 08:43:51 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2017-04-25 01:47:32 -0400 |
commit | ee71d16d22bb268c1f6a64ef6d3654ace5f1e8c7 (patch) | |
tree | 8e8ecc1da0ba8947a9b024a435262460d67caeff | |
parent | 5037c22c53603acd4e8c465d750fdd604c600bd3 (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.h | 4 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 9 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 4 | ||||
-rw-r--r-- | arch/s390/mm/gmap.c | 2 | ||||
-rw-r--r-- | arch/s390/mm/gup.c | 2 | ||||
-rw-r--r-- | arch/s390/mm/mmap.c | 31 | ||||
-rw-r--r-- | 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 @@ | |||
8 | 8 | ||
9 | #include <uapi/asm/mman.h> | 9 | #include <uapi/asm/mman.h> |
10 | 10 | ||
11 | #ifndef __ASSEMBLY__ | ||
12 | int 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 | ||
173 | int 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 | |||
184 | static unsigned long | 175 | static unsigned long |
185 | s390_get_unmapped_area(struct file *filp, unsigned long addr, | 176 | s390_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) |