diff options
author | Michel Lespinasse <walken@google.com> | 2012-12-11 19:02:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 20:22:26 -0500 |
commit | 394ef6403abc36900d9303395a49a72d32666f2a (patch) | |
tree | 74d061c96c5ef1aa9250aa152e27058bc19f5324 /arch/arm/mm/mmap.c | |
parent | b6661861777940b05934169d8a3f9207cd718996 (diff) |
mm: use vm_unmapped_area() on arm architecture
Update the arm arch_get_unmapped_area[_topdown] functions to make use of
vm_unmapped_area() instead of implementing a brute force search.
[akpm@linux-foundation.org: remove now-unused COLOUR_ALIGN_DOWN()]
Signed-off-by: Michel Lespinasse <walken@google.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/arm/mm/mmap.c')
-rw-r--r-- | arch/arm/mm/mmap.c | 132 |
1 files changed, 23 insertions, 109 deletions
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index ce8cb1970d7a..2065b603763c 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c | |||
@@ -11,18 +11,6 @@ | |||
11 | #include <linux/random.h> | 11 | #include <linux/random.h> |
12 | #include <asm/cachetype.h> | 12 | #include <asm/cachetype.h> |
13 | 13 | ||
14 | static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr, | ||
15 | unsigned long pgoff) | ||
16 | { | ||
17 | unsigned long base = addr & ~(SHMLBA-1); | ||
18 | unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1); | ||
19 | |||
20 | if (base + off <= addr) | ||
21 | return base + off; | ||
22 | |||
23 | return base - off; | ||
24 | } | ||
25 | |||
26 | #define COLOUR_ALIGN(addr,pgoff) \ | 14 | #define COLOUR_ALIGN(addr,pgoff) \ |
27 | ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ | 15 | ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ |
28 | (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) | 16 | (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) |
@@ -69,9 +57,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
69 | { | 57 | { |
70 | struct mm_struct *mm = current->mm; | 58 | struct mm_struct *mm = current->mm; |
71 | struct vm_area_struct *vma; | 59 | struct vm_area_struct *vma; |
72 | unsigned long start_addr; | ||
73 | int do_align = 0; | 60 | int do_align = 0; |
74 | int aliasing = cache_is_vipt_aliasing(); | 61 | int aliasing = cache_is_vipt_aliasing(); |
62 | struct vm_unmapped_area_info info; | ||
75 | 63 | ||
76 | /* | 64 | /* |
77 | * We only need to do colour alignment if either the I or D | 65 | * We only need to do colour alignment if either the I or D |
@@ -104,46 +92,14 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
104 | (!vma || addr + len <= vma->vm_start)) | 92 | (!vma || addr + len <= vma->vm_start)) |
105 | return addr; | 93 | return addr; |
106 | } | 94 | } |
107 | if (len > mm->cached_hole_size) { | ||
108 | start_addr = addr = mm->free_area_cache; | ||
109 | } else { | ||
110 | start_addr = addr = mm->mmap_base; | ||
111 | mm->cached_hole_size = 0; | ||
112 | } | ||
113 | 95 | ||
114 | full_search: | 96 | info.flags = 0; |
115 | if (do_align) | 97 | info.length = len; |
116 | addr = COLOUR_ALIGN(addr, pgoff); | 98 | info.low_limit = mm->mmap_base; |
117 | else | 99 | info.high_limit = TASK_SIZE; |
118 | addr = PAGE_ALIGN(addr); | 100 | info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; |
119 | 101 | info.align_offset = pgoff << PAGE_SHIFT; | |
120 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | 102 | return vm_unmapped_area(&info); |
121 | /* At this point: (!vma || addr < vma->vm_end). */ | ||
122 | if (TASK_SIZE - len < addr) { | ||
123 | /* | ||
124 | * Start a new search - just in case we missed | ||
125 | * some holes. | ||
126 | */ | ||
127 | if (start_addr != TASK_UNMAPPED_BASE) { | ||
128 | start_addr = addr = TASK_UNMAPPED_BASE; | ||
129 | mm->cached_hole_size = 0; | ||
130 | goto full_search; | ||
131 | } | ||
132 | return -ENOMEM; | ||
133 | } | ||
134 | if (!vma || addr + len <= vma->vm_start) { | ||
135 | /* | ||
136 | * Remember the place where we stopped the search: | ||
137 | */ | ||
138 | mm->free_area_cache = addr + len; | ||
139 | return addr; | ||
140 | } | ||
141 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
142 | mm->cached_hole_size = vma->vm_start - addr; | ||
143 | addr = vma->vm_end; | ||
144 | if (do_align) | ||
145 | addr = COLOUR_ALIGN(addr, pgoff); | ||
146 | } | ||
147 | } | 103 | } |
148 | 104 | ||
149 | unsigned long | 105 | unsigned long |
@@ -156,6 +112,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
156 | unsigned long addr = addr0; | 112 | unsigned long addr = addr0; |
157 | int do_align = 0; | 113 | int do_align = 0; |
158 | int aliasing = cache_is_vipt_aliasing(); | 114 | int aliasing = cache_is_vipt_aliasing(); |
115 | struct vm_unmapped_area_info info; | ||
159 | 116 | ||
160 | /* | 117 | /* |
161 | * We only need to do colour alignment if either the I or D | 118 | * We only need to do colour alignment if either the I or D |
@@ -187,70 +144,27 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
187 | return addr; | 144 | return addr; |
188 | } | 145 | } |
189 | 146 | ||
190 | /* check if free_area_cache is useful for us */ | 147 | info.flags = VM_UNMAPPED_AREA_TOPDOWN; |
191 | if (len <= mm->cached_hole_size) { | 148 | info.length = len; |
192 | mm->cached_hole_size = 0; | 149 | info.low_limit = PAGE_SIZE; |
193 | mm->free_area_cache = mm->mmap_base; | 150 | info.high_limit = mm->mmap_base; |
194 | } | 151 | info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; |
195 | 152 | info.align_offset = pgoff << PAGE_SHIFT; | |
196 | /* either no address requested or can't fit in requested address hole */ | 153 | addr = vm_unmapped_area(&info); |
197 | addr = mm->free_area_cache; | ||
198 | if (do_align) { | ||
199 | unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff); | ||
200 | addr = base + len; | ||
201 | } | ||
202 | |||
203 | /* make sure it can fit in the remaining address space */ | ||
204 | if (addr > len) { | ||
205 | vma = find_vma(mm, addr-len); | ||
206 | if (!vma || addr <= vma->vm_start) | ||
207 | /* remember the address as a hint for next time */ | ||
208 | return (mm->free_area_cache = addr-len); | ||
209 | } | ||
210 | |||
211 | if (mm->mmap_base < len) | ||
212 | goto bottomup; | ||
213 | |||
214 | addr = mm->mmap_base - len; | ||
215 | if (do_align) | ||
216 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
217 | |||
218 | do { | ||
219 | /* | ||
220 | * Lookup failure means no vma is above this address, | ||
221 | * else if new region fits below vma->vm_start, | ||
222 | * return with success: | ||
223 | */ | ||
224 | vma = find_vma(mm, addr); | ||
225 | if (!vma || addr+len <= vma->vm_start) | ||
226 | /* remember the address as a hint for next time */ | ||
227 | return (mm->free_area_cache = addr); | ||
228 | 154 | ||
229 | /* remember the largest hole we saw so far */ | ||
230 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
231 | mm->cached_hole_size = vma->vm_start - addr; | ||
232 | |||
233 | /* try just below the current vma->vm_start */ | ||
234 | addr = vma->vm_start - len; | ||
235 | if (do_align) | ||
236 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
237 | } while (len < vma->vm_start); | ||
238 | |||
239 | bottomup: | ||
240 | /* | 155 | /* |
241 | * A failed mmap() very likely causes application failure, | 156 | * A failed mmap() very likely causes application failure, |
242 | * so fall back to the bottom-up function here. This scenario | 157 | * so fall back to the bottom-up function here. This scenario |
243 | * can happen with large stack limits and large mmap() | 158 | * can happen with large stack limits and large mmap() |
244 | * allocations. | 159 | * allocations. |
245 | */ | 160 | */ |
246 | mm->cached_hole_size = ~0UL; | 161 | if (addr & ~PAGE_MASK) { |
247 | mm->free_area_cache = TASK_UNMAPPED_BASE; | 162 | VM_BUG_ON(addr != -ENOMEM); |
248 | addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); | 163 | info.flags = 0; |
249 | /* | 164 | info.low_limit = mm->mmap_base; |
250 | * Restore the topdown base: | 165 | info.high_limit = TASK_SIZE; |
251 | */ | 166 | addr = vm_unmapped_area(&info); |
252 | mm->free_area_cache = mm->mmap_base; | 167 | } |
253 | mm->cached_hole_size = ~0UL; | ||
254 | 168 | ||
255 | return addr; | 169 | return addr; |
256 | } | 170 | } |