diff options
author | Christoph Lameter <clameter@engr.sgi.com> | 2006-02-28 16:59:16 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-28 20:53:44 -0800 |
commit | e8788c0cce63e0cc8689a123d1ce0af1e28cd583 (patch) | |
tree | 9350d9fc11a5a6ca81d4ee063278999e4dfe869d /mm/rmap.c | |
parent | 6af6aab34a88050c8270ef75ddbdefef5c1dca00 (diff) | |
download | linux-e8788c0cce63e0cc8689a123d1ce0af1e28cd583.tar.gz linux-e8788c0cce63e0cc8689a123d1ce0af1e28cd583.tar.bz2 linux-e8788c0cce63e0cc8689a123d1ce0af1e28cd583.zip |
[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>
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/mm/rmap.c b/mm/rmap.c index df2c41c2a9a2..d8ce5ff61454 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -212,25 +212,33 @@ out: * through real pte's pointing to valid pages and then releasing * the page from the swap cache. * - * Must hold page lock on page. + * Must hold page lock on page and mmap_sem of one vma that contains + * the page. */ void remove_from_swap(struct page *page) { struct anon_vma *anon_vma; struct vm_area_struct *vma; + unsigned long mapping; - if (!PageAnon(page) || !PageSwapCache(page)) + if (!PageSwapCache(page)) return; - anon_vma = page_lock_anon_vma(page); - if (!anon_vma) + mapping = (unsigned long)page->mapping; + + if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0) return; + /* + * We hold the mmap_sem lock. So no need to call page_lock_anon_vma. + */ + anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON); + spin_lock(&anon_vma->lock); + list_for_each_entry(vma, &anon_vma->head, anon_vma_node) remove_vma_swap(vma, page); spin_unlock(&anon_vma->lock); - delete_from_swap_cache(page); } EXPORT_SYMBOL(remove_from_swap); |