mm: speculative page references
If we can be sure that elevating the page_count on a pagecache page will pin it, we can speculatively run this operation, and subsequently check to see if we hit the right page rather than relying on holding a lock or otherwise pinning a reference to the page. This can be done if get_page/put_page behaves consistently throughout the whole tree (ie. if we "get" the page after it has been used for something else, we must be able to free it with a put_page). Actually, there is a period where the count behaves differently: when the page is free or if it is a constituent page of a compound page. We need an atomic_inc_not_zero operation to ensure we don't try to grab the page in either case. This patch introduces the core locking protocol to the pagecache (ie. adds page_cache_get_speculative, and tweaks some update-side code to make it work). Thanks to Hugh for pointing out an improvement to the algorithm setting page_count to zero when we have control of all references, in order to hold off speculative getters. [kamezawa.hiroyu@jp.fujitsu.com: fix migration_entry_wait()] [hugh@veritas.com: fix add_to_page_cache] [akpm@linux-foundation.org: repair a comment] Signed-off-by: Nick Piggin <npiggin@suse.de> Cc: Jeff Garzik <jeff@garzik.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Hugh Dickins <hugh@veritas.com> Cc: "Paul E. McKenney" <paulmck@us.ibm.com> Reviewed-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Hugh Dickins <hugh@veritas.com> Acked-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
47feff2c8e
commit
e286781d5f
@@ -64,7 +64,7 @@ void show_swap_cache_info(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* add_to_swap_cache resembles add_to_page_cache on swapper_space,
|
||||
* add_to_swap_cache resembles add_to_page_cache_locked on swapper_space,
|
||||
* but sets SwapCache flag and private instead of mapping and index.
|
||||
*/
|
||||
int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
|
||||
@@ -76,19 +76,26 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
|
||||
BUG_ON(PagePrivate(page));
|
||||
error = radix_tree_preload(gfp_mask);
|
||||
if (!error) {
|
||||
page_cache_get(page);
|
||||
SetPageSwapCache(page);
|
||||
set_page_private(page, entry.val);
|
||||
|
||||
write_lock_irq(&swapper_space.tree_lock);
|
||||
error = radix_tree_insert(&swapper_space.page_tree,
|
||||
entry.val, page);
|
||||
if (!error) {
|
||||
page_cache_get(page);
|
||||
SetPageSwapCache(page);
|
||||
set_page_private(page, entry.val);
|
||||
if (likely(!error)) {
|
||||
total_swapcache_pages++;
|
||||
__inc_zone_page_state(page, NR_FILE_PAGES);
|
||||
INC_CACHE_INFO(add_total);
|
||||
}
|
||||
write_unlock_irq(&swapper_space.tree_lock);
|
||||
radix_tree_preload_end();
|
||||
|
||||
if (unlikely(error)) {
|
||||
set_page_private(page, 0UL);
|
||||
ClearPageSwapCache(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
Reference in New Issue
Block a user