diff options
Diffstat (limited to 'arch/mips/mm/mmap.c')
-rw-r--r-- | arch/mips/mm/mmap.c | 111 |
1 files changed, 17 insertions, 94 deletions
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index 302d779d5b0d..d9be7540a6be 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c | |||
@@ -45,18 +45,6 @@ static unsigned long mmap_base(unsigned long rnd) | |||
45 | return PAGE_ALIGN(TASK_SIZE - gap - rnd); | 45 | return PAGE_ALIGN(TASK_SIZE - gap - rnd); |
46 | } | 46 | } |
47 | 47 | ||
48 | static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr, | ||
49 | unsigned long pgoff) | ||
50 | { | ||
51 | unsigned long base = addr & ~shm_align_mask; | ||
52 | unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask; | ||
53 | |||
54 | if (base + off <= addr) | ||
55 | return base + off; | ||
56 | |||
57 | return base - off; | ||
58 | } | ||
59 | |||
60 | #define COLOUR_ALIGN(addr, pgoff) \ | 48 | #define COLOUR_ALIGN(addr, pgoff) \ |
61 | ((((addr) + shm_align_mask) & ~shm_align_mask) + \ | 49 | ((((addr) + shm_align_mask) & ~shm_align_mask) + \ |
62 | (((pgoff) << PAGE_SHIFT) & shm_align_mask)) | 50 | (((pgoff) << PAGE_SHIFT) & shm_align_mask)) |
@@ -71,6 +59,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, | |||
71 | struct vm_area_struct *vma; | 59 | struct vm_area_struct *vma; |
72 | unsigned long addr = addr0; | 60 | unsigned long addr = addr0; |
73 | int do_color_align; | 61 | int do_color_align; |
62 | struct vm_unmapped_area_info info; | ||
74 | 63 | ||
75 | if (unlikely(len > TASK_SIZE)) | 64 | if (unlikely(len > TASK_SIZE)) |
76 | return -ENOMEM; | 65 | return -ENOMEM; |
@@ -107,97 +96,31 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, | |||
107 | return addr; | 96 | return addr; |
108 | } | 97 | } |
109 | 98 | ||
110 | if (dir == UP) { | 99 | info.length = len; |
111 | addr = mm->mmap_base; | 100 | info.align_mask = do_color_align ? (PAGE_MASK & shm_align_mask) : 0; |
112 | if (do_color_align) | 101 | info.align_offset = pgoff << PAGE_SHIFT; |
113 | addr = COLOUR_ALIGN(addr, pgoff); | ||
114 | else | ||
115 | addr = PAGE_ALIGN(addr); | ||
116 | 102 | ||
117 | for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { | 103 | if (dir == DOWN) { |
118 | /* At this point: (!vma || addr < vma->vm_end). */ | 104 | info.flags = VM_UNMAPPED_AREA_TOPDOWN; |
119 | if (TASK_SIZE - len < addr) | 105 | info.low_limit = PAGE_SIZE; |
120 | return -ENOMEM; | 106 | info.high_limit = mm->mmap_base; |
121 | if (!vma || addr + len <= vma->vm_start) | 107 | addr = vm_unmapped_area(&info); |
122 | return addr; | 108 | |
123 | addr = vma->vm_end; | 109 | if (!(addr & ~PAGE_MASK)) |
124 | if (do_color_align) | 110 | return addr; |
125 | addr = COLOUR_ALIGN(addr, pgoff); | ||
126 | } | ||
127 | } else { | ||
128 | /* check if free_area_cache is useful for us */ | ||
129 | if (len <= mm->cached_hole_size) { | ||
130 | mm->cached_hole_size = 0; | ||
131 | mm->free_area_cache = mm->mmap_base; | ||
132 | } | ||
133 | 111 | ||
134 | /* | ||
135 | * either no address requested, or the mapping can't fit into | ||
136 | * the requested address hole | ||
137 | */ | ||
138 | addr = mm->free_area_cache; | ||
139 | if (do_color_align) { | ||
140 | unsigned long base = | ||
141 | COLOUR_ALIGN_DOWN(addr - len, pgoff); | ||
142 | addr = base + len; | ||
143 | } | ||
144 | |||
145 | /* make sure it can fit in the remaining address space */ | ||
146 | if (likely(addr > len)) { | ||
147 | vma = find_vma(mm, addr - len); | ||
148 | if (!vma || addr <= vma->vm_start) { | ||
149 | /* cache the address as a hint for next time */ | ||
150 | return mm->free_area_cache = addr - len; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | if (unlikely(mm->mmap_base < len)) | ||
155 | goto bottomup; | ||
156 | |||
157 | addr = mm->mmap_base - len; | ||
158 | if (do_color_align) | ||
159 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
160 | |||
161 | do { | ||
162 | /* | ||
163 | * Lookup failure means no vma is above this address, | ||
164 | * else if new region fits below vma->vm_start, | ||
165 | * return with success: | ||
166 | */ | ||
167 | vma = find_vma(mm, addr); | ||
168 | if (likely(!vma || addr + len <= vma->vm_start)) { | ||
169 | /* cache the address as a hint for next time */ | ||
170 | return mm->free_area_cache = addr; | ||
171 | } | ||
172 | |||
173 | /* remember the largest hole we saw so far */ | ||
174 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
175 | mm->cached_hole_size = vma->vm_start - addr; | ||
176 | |||
177 | /* try just below the current vma->vm_start */ | ||
178 | addr = vma->vm_start - len; | ||
179 | if (do_color_align) | ||
180 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
181 | } while (likely(len < vma->vm_start)); | ||
182 | |||
183 | bottomup: | ||
184 | /* | 112 | /* |
185 | * A failed mmap() very likely causes application failure, | 113 | * A failed mmap() very likely causes application failure, |
186 | * so fall back to the bottom-up function here. This scenario | 114 | * so fall back to the bottom-up function here. This scenario |
187 | * can happen with large stack limits and large mmap() | 115 | * can happen with large stack limits and large mmap() |
188 | * allocations. | 116 | * allocations. |
189 | */ | 117 | */ |
190 | mm->cached_hole_size = ~0UL; | ||
191 | mm->free_area_cache = TASK_UNMAPPED_BASE; | ||
192 | addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); | ||
193 | /* | ||
194 | * Restore the topdown base: | ||
195 | */ | ||
196 | mm->free_area_cache = mm->mmap_base; | ||
197 | mm->cached_hole_size = ~0UL; | ||
198 | |||
199 | return addr; | ||
200 | } | 118 | } |
119 | |||
120 | info.flags = 0; | ||
121 | info.low_limit = mm->mmap_base; | ||
122 | info.high_limit = TASK_SIZE; | ||
123 | return vm_unmapped_area(&info); | ||
201 | } | 124 | } |
202 | 125 | ||
203 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0, | 126 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0, |