Commit 0fb1d9bcbcf701a45835aa150c57ca54ea685bfa
1 parent
f481bfafd3
Exists in
master
and in
7 other branches
[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: Martin Schwidefsky <schwidefsky@de.ibm.com>
Showing 2 changed files with 35 additions and 14 deletions Side-by-side Diff
arch/s390/include/asm/mman.h
... | ... | @@ -22,5 +22,10 @@ |
22 | 22 | #define MCL_CURRENT 1 /* lock all current mappings */ |
23 | 23 | #define MCL_FUTURE 2 /* lock all future mappings */ |
24 | 24 | |
25 | +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) && defined(CONFIG_64BIT) | |
26 | +int s390_mmap_check(unsigned long addr, unsigned long len); | |
27 | +#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len) | |
28 | +#endif | |
29 | + | |
25 | 30 | #endif /* __S390_MMAN_H__ */ |
arch/s390/mm/mmap.c
... | ... | @@ -89,42 +89,58 @@ |
89 | 89 | |
90 | 90 | #else |
91 | 91 | |
92 | +int s390_mmap_check(unsigned long addr, unsigned long len) | |
93 | +{ | |
94 | + if (!test_thread_flag(TIF_31BIT) && | |
95 | + len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) | |
96 | + return crst_table_upgrade(current->mm, 1UL << 53); | |
97 | + return 0; | |
98 | +} | |
99 | + | |
92 | 100 | static unsigned long |
93 | 101 | s390_get_unmapped_area(struct file *filp, unsigned long addr, |
94 | 102 | unsigned long len, unsigned long pgoff, unsigned long flags) |
95 | 103 | { |
96 | 104 | struct mm_struct *mm = current->mm; |
105 | + unsigned long area; | |
97 | 106 | int rc; |
98 | 107 | |
99 | - addr = arch_get_unmapped_area(filp, addr, len, pgoff, flags); | |
100 | - if (addr & ~PAGE_MASK) | |
101 | - return addr; | |
102 | - if (unlikely(mm->context.asce_limit < addr + len)) { | |
103 | - rc = crst_table_upgrade(mm, addr + len); | |
108 | + area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); | |
109 | + if (!(area & ~PAGE_MASK)) | |
110 | + return area; | |
111 | + if (area == -ENOMEM && | |
112 | + !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) { | |
113 | + /* Upgrade the page table to 4 levels and retry. */ | |
114 | + rc = crst_table_upgrade(mm, 1UL << 53); | |
104 | 115 | if (rc) |
105 | 116 | return (unsigned long) rc; |
117 | + area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); | |
106 | 118 | } |
107 | - return addr; | |
119 | + return area; | |
108 | 120 | } |
109 | 121 | |
110 | 122 | static unsigned long |
111 | -s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |
123 | +s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, | |
112 | 124 | const unsigned long len, const unsigned long pgoff, |
113 | 125 | const unsigned long flags) |
114 | 126 | { |
115 | 127 | struct mm_struct *mm = current->mm; |
116 | - unsigned long addr = addr0; | |
128 | + unsigned long area; | |
117 | 129 | int rc; |
118 | 130 | |
119 | - addr = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); | |
120 | - if (addr & ~PAGE_MASK) | |
121 | - return addr; | |
122 | - if (unlikely(mm->context.asce_limit < addr + len)) { | |
123 | - rc = crst_table_upgrade(mm, addr + len); | |
131 | + area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); | |
132 | + if (!(area & ~PAGE_MASK)) | |
133 | + return area; | |
134 | + if (area == -ENOMEM && | |
135 | + !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) { | |
136 | + /* Upgrade the page table to 4 levels and retry. */ | |
137 | + rc = crst_table_upgrade(mm, 1UL << 53); | |
124 | 138 | if (rc) |
125 | 139 | return (unsigned long) rc; |
140 | + area = arch_get_unmapped_area_topdown(filp, addr, len, | |
141 | + pgoff, flags); | |
126 | 142 | } |
127 | - return addr; | |
143 | + return area; | |
128 | 144 | } |
129 | 145 | /* |
130 | 146 | * This function, called very early during the creation of a new |