1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/personality.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30#include <asm/pgalloc.h>
31#include <asm/compat.h>
32
33
34
35
36
37
38#define MIN_GAP (128*1024*1024)
39#define MAX_GAP (STACK_TOP/6*5)
40
41static inline unsigned long mmap_base(void)
42{
43 unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
44
45 if (gap < MIN_GAP)
46 gap = MIN_GAP;
47 else if (gap > MAX_GAP)
48 gap = MAX_GAP;
49
50 return STACK_TOP - (gap & PAGE_MASK);
51}
52
53static inline int mmap_is_legacy(void)
54{
55#ifdef CONFIG_64BIT
56
57
58
59 if (!is_compat_task())
60 return 1;
61#endif
62 return sysctl_legacy_va_layout ||
63 (current->personality & ADDR_COMPAT_LAYOUT) ||
64 current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY;
65}
66
67#ifndef CONFIG_64BIT
68
69
70
71
72
73void arch_pick_mmap_layout(struct mm_struct *mm)
74{
75
76
77
78
79 if (mmap_is_legacy()) {
80 mm->mmap_base = TASK_UNMAPPED_BASE;
81 mm->get_unmapped_area = arch_get_unmapped_area;
82 mm->unmap_area = arch_unmap_area;
83 } else {
84 mm->mmap_base = mmap_base();
85 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
86 mm->unmap_area = arch_unmap_area_topdown;
87 }
88}
89EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
90
91#else
92
93int s390_mmap_check(unsigned long addr, unsigned long len)
94{
95 if (!is_compat_task() &&
96 len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
97 return crst_table_upgrade(current->mm, 1UL << 53);
98 return 0;
99}
100
101static unsigned long
102s390_get_unmapped_area(struct file *filp, unsigned long addr,
103 unsigned long len, unsigned long pgoff, unsigned long flags)
104{
105 struct mm_struct *mm = current->mm;
106 unsigned long area;
107 int rc;
108
109 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
110 if (!(area & ~PAGE_MASK))
111 return area;
112 if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
113
114 rc = crst_table_upgrade(mm, 1UL << 53);
115 if (rc)
116 return (unsigned long) rc;
117 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
118 }
119 return area;
120}
121
122static unsigned long
123s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
124 const unsigned long len, const unsigned long pgoff,
125 const unsigned long flags)
126{
127 struct mm_struct *mm = current->mm;
128 unsigned long area;
129 int rc;
130
131 area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
132 if (!(area & ~PAGE_MASK))
133 return area;
134 if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
135
136 rc = crst_table_upgrade(mm, 1UL << 53);
137 if (rc)
138 return (unsigned long) rc;
139 area = arch_get_unmapped_area_topdown(filp, addr, len,
140 pgoff, flags);
141 }
142 return area;
143}
144
145
146
147
148void arch_pick_mmap_layout(struct mm_struct *mm)
149{
150
151
152
153
154 if (mmap_is_legacy()) {
155 mm->mmap_base = TASK_UNMAPPED_BASE;
156 mm->get_unmapped_area = s390_get_unmapped_area;
157 mm->unmap_area = arch_unmap_area;
158 } else {
159 mm->mmap_base = mmap_base();
160 mm->get_unmapped_area = s390_get_unmapped_area_topdown;
161 mm->unmap_area = arch_unmap_area_topdown;
162 }
163}
164EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
165
166#endif
167