Commit 016eb4a0 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] invalidate_complete_page() race fix

If a CPU faults this page into pagetables after invalidate_mapping_pages()
checked page_mapped(), invalidate_complete_page() will still proceed to remove
the page from pagecache.  This leaves the page-faulting process with a
detached page.  If it was MAP_SHARED then file data loss will ensue.

Fix that up by checking the page's refcount after taking tree_lock.

Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: <stable@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3665d0e5
...@@ -68,10 +68,10 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) ...@@ -68,10 +68,10 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
return 0; return 0;
write_lock_irq(&mapping->tree_lock); write_lock_irq(&mapping->tree_lock);
if (PageDirty(page)) { if (PageDirty(page))
write_unlock_irq(&mapping->tree_lock); goto failed;
return 0; if (page_count(page) != 2) /* caller's ref + pagecache ref */
} goto failed;
BUG_ON(PagePrivate(page)); BUG_ON(PagePrivate(page));
__remove_from_page_cache(page); __remove_from_page_cache(page);
...@@ -79,6 +79,9 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) ...@@ -79,6 +79,9 @@ invalidate_complete_page(struct address_space *mapping, struct page *page)
ClearPageUptodate(page); ClearPageUptodate(page);
page_cache_release(page); /* pagecache ref */ page_cache_release(page); /* pagecache ref */
return 1; return 1;
failed:
write_unlock_irq(&mapping->tree_lock);
return 0;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment