aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorChristoph Lameter <clameter@engr.sgi.com>2006-02-28 19:59:16 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-28 23:53:44 -0500
commite8788c0cce63e0cc8689a123d1ce0af1e28cd583 (patch)
tree9350d9fc11a5a6ca81d4ee063278999e4dfe869d /mm
parent6af6aab34a88050c8270ef75ddbdefef5c1dca00 (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>
Diffstat (limited to 'mm')
-rw-r--r--mm/rmap.c18
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:
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 */
217void remove_from_swap(struct page *page) 218void 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}
236EXPORT_SYMBOL(remove_from_swap); 244EXPORT_SYMBOL(remove_from_swap);