mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
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. [[email protected]: fix migration_entry_wait()] [[email protected]: fix add_to_page_cache] [[email protected]: repair a comment] Signed-off-by: Nick Piggin <[email protected]> Cc: Jeff Garzik <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Reviewed-by: Peter Zijlstra <[email protected]> Signed-off-by: Daisuke Nishimura <[email protected]> Signed-off-by: KAMEZAWA Hiroyuki <[email protected]> Signed-off-by: KOSAKI Motohiro <[email protected]> Signed-off-by: Hugh Dickins <[email protected]> Acked-by: Nick Piggin <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
47feff2c8e
commit
e286781d5f
7 changed files with 227 additions and 45 deletions
20
mm/migrate.c
20
mm/migrate.c
|
|
@ -285,7 +285,15 @@ void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
|
|||
|
||||
page = migration_entry_to_page(entry);
|
||||
|
||||
get_page(page);
|
||||
/*
|
||||
* Once radix-tree replacement of page migration started, page_count
|
||||
* *must* be zero. And, we don't want to call wait_on_page_locked()
|
||||
* against a page without get_page().
|
||||
* So, we use get_page_unless_zero(), here. Even failed, page fault
|
||||
* will occur again.
|
||||
*/
|
||||
if (!get_page_unless_zero(page))
|
||||
goto out;
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
wait_on_page_locked(page);
|
||||
put_page(page);
|
||||
|
|
@ -305,6 +313,7 @@ out:
|
|||
static int migrate_page_move_mapping(struct address_space *mapping,
|
||||
struct page *newpage, struct page *page)
|
||||
{
|
||||
int expected_count;
|
||||
void **pslot;
|
||||
|
||||
if (!mapping) {
|
||||
|
|
@ -319,12 +328,18 @@ static int migrate_page_move_mapping(struct address_space *mapping,
|
|||
pslot = radix_tree_lookup_slot(&mapping->page_tree,
|
||||
page_index(page));
|
||||
|
||||
if (page_count(page) != 2 + !!PagePrivate(page) ||
|
||||
expected_count = 2 + !!PagePrivate(page);
|
||||
if (page_count(page) != expected_count ||
|
||||
(struct page *)radix_tree_deref_slot(pslot) != page) {
|
||||
write_unlock_irq(&mapping->tree_lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!page_freeze_refs(page, expected_count)) {
|
||||
write_unlock_irq(&mapping->tree_lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we know that no one else is looking at the page.
|
||||
*/
|
||||
|
|
@ -338,6 +353,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
|
|||
|
||||
radix_tree_replace_slot(pslot, newpage);
|
||||
|
||||
page_unfreeze_refs(page, expected_count);
|
||||
/*
|
||||
* Drop cache reference from old page.
|
||||
* We know this isn't the last reference.
|
||||
|
|
|
|||
Loading…
Reference in a new issue