diff options
| author | Christoph Lameter <clameter@engr.sgi.com> | 2006-02-28 19:59:16 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-28 23:53:44 -0500 |
| commit | e8788c0cce63e0cc8689a123d1ce0af1e28cd583 (patch) | |
| tree | 9350d9fc11a5a6ca81d4ee063278999e4dfe869d | |
| parent | 6af6aab34a88050c8270ef75ddbdefef5c1dca00 (diff) | |
[PATCH] remove_from_swap: fix locking
remove_from_swap() currently attempts to use page_lock_anon_vma to obtain
an anon_vma lock. That is not working since the page may have been
remapped via swap ptes in order to move the page.
However, do_migrate_pages() obtain the mmap_sem lock and therefore there is
a guarantee that the anonymous vma will not vanish from under us. There is
therefore no need to use page_lock_anon_vma.
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Acked-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | mm/rmap.c | 18 |
1 files changed, 13 insertions, 5 deletions
| @@ -212,25 +212,33 @@ out: | |||
| 212 | * through real pte's pointing to valid pages and then releasing | 212 | * through real pte's pointing to valid pages and then releasing |
| 213 | * the page from the swap cache. | 213 | * the page from the swap cache. |
| 214 | * | 214 | * |
| 215 | * Must hold page lock on page. | 215 | * Must hold page lock on page and mmap_sem of one vma that contains |
| 216 | * the page. | ||
| 216 | */ | 217 | */ |
| 217 | void remove_from_swap(struct page *page) | 218 | void remove_from_swap(struct page *page) |
| 218 | { | 219 | { |
| 219 | struct anon_vma *anon_vma; | 220 | struct anon_vma *anon_vma; |
| 220 | struct vm_area_struct *vma; | 221 | struct vm_area_struct *vma; |
| 222 | unsigned long mapping; | ||
| 221 | 223 | ||
| 222 | if (!PageAnon(page) || !PageSwapCache(page)) | 224 | if (!PageSwapCache(page)) |
| 223 | return; | 225 | return; |
| 224 | 226 | ||
| 225 | anon_vma = page_lock_anon_vma(page); | 227 | mapping = (unsigned long)page->mapping; |
| 226 | if (!anon_vma) | 228 | |
| 229 | if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0) | ||
| 227 | return; | 230 | return; |
| 228 | 231 | ||
| 232 | /* | ||
| 233 | * We hold the mmap_sem lock. So no need to call page_lock_anon_vma. | ||
| 234 | */ | ||
| 235 | anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON); | ||
| 236 | spin_lock(&anon_vma->lock); | ||
| 237 | |||
| 229 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) | 238 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) |
| 230 | remove_vma_swap(vma, page); | 239 | remove_vma_swap(vma, page); |
| 231 | 240 | ||
| 232 | spin_unlock(&anon_vma->lock); | 241 | spin_unlock(&anon_vma->lock); |
| 233 | |||
| 234 | delete_from_swap_cache(page); | 242 | delete_from_swap_cache(page); |
| 235 | } | 243 | } |
| 236 | EXPORT_SYMBOL(remove_from_swap); | 244 | EXPORT_SYMBOL(remove_from_swap); |
