diff options
author | Andi Kleen <ak@suse.de> | 2005-05-20 17:27:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-20 18:48:20 -0400 |
commit | 7856dfeb23c16ef3d8dac8871b4d5b93c70b59b9 (patch) | |
tree | 0e9f799c3882dce14b49356c6db10bb6f4ba1713 /mm | |
parent | c4d1fcf3a2ea89b6d6221fa8b4588c77aff50995 (diff) |
[PATCH] x86_64: Fixed guard page handling again in iounmap
Caused oopses again. Also fix potential mismatch in checking if
change_page_attr was needed.
To do it without races I needed to change mm/vmalloc.c to export a
__remove_vm_area that does not take vmlist lock.
Noticed by Terence Ripperda and based on a patch of his.
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/vmalloc.c | 33 |
1 files changed, 20 insertions, 13 deletions
diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 2bd83e5c2bbf..8ff16a1eee6a 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c | |||
@@ -248,31 +248,20 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) | |||
248 | return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); | 248 | return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); |
249 | } | 249 | } |
250 | 250 | ||
251 | /** | 251 | /* Caller must hold vmlist_lock */ |
252 | * remove_vm_area - find and remove a contingous kernel virtual area | 252 | struct vm_struct *__remove_vm_area(void *addr) |
253 | * | ||
254 | * @addr: base address | ||
255 | * | ||
256 | * Search for the kernel VM area starting at @addr, and remove it. | ||
257 | * This function returns the found VM area, but using it is NOT safe | ||
258 | * on SMP machines. | ||
259 | */ | ||
260 | struct vm_struct *remove_vm_area(void *addr) | ||
261 | { | 253 | { |
262 | struct vm_struct **p, *tmp; | 254 | struct vm_struct **p, *tmp; |
263 | 255 | ||
264 | write_lock(&vmlist_lock); | ||
265 | for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) { | 256 | for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) { |
266 | if (tmp->addr == addr) | 257 | if (tmp->addr == addr) |
267 | goto found; | 258 | goto found; |
268 | } | 259 | } |
269 | write_unlock(&vmlist_lock); | ||
270 | return NULL; | 260 | return NULL; |
271 | 261 | ||
272 | found: | 262 | found: |
273 | unmap_vm_area(tmp); | 263 | unmap_vm_area(tmp); |
274 | *p = tmp->next; | 264 | *p = tmp->next; |
275 | write_unlock(&vmlist_lock); | ||
276 | 265 | ||
277 | /* | 266 | /* |
278 | * Remove the guard page. | 267 | * Remove the guard page. |
@@ -281,6 +270,24 @@ found: | |||
281 | return tmp; | 270 | return tmp; |
282 | } | 271 | } |
283 | 272 | ||
273 | /** | ||
274 | * remove_vm_area - find and remove a contingous kernel virtual area | ||
275 | * | ||
276 | * @addr: base address | ||
277 | * | ||
278 | * Search for the kernel VM area starting at @addr, and remove it. | ||
279 | * This function returns the found VM area, but using it is NOT safe | ||
280 | * on SMP machines, except for its size or flags. | ||
281 | */ | ||
282 | struct vm_struct *remove_vm_area(void *addr) | ||
283 | { | ||
284 | struct vm_struct *v; | ||
285 | write_lock(&vmlist_lock); | ||
286 | v = __remove_vm_area(addr); | ||
287 | write_unlock(&vmlist_lock); | ||
288 | return v; | ||
289 | } | ||
290 | |||
284 | void __vunmap(void *addr, int deallocate_pages) | 291 | void __vunmap(void *addr, int deallocate_pages) |
285 | { | 292 | { |
286 | struct vm_struct *area; | 293 | struct vm_struct *area; |