aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2013-02-22 19:35:06 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-23 20:50:19 -0500
commit8aafa6a485ae77ce4a49eb1280f3d2c6074a03fb (patch)
treeb267e3bc9602e2a7975b7973036beaa79c0ab148
parentee0ea59cf9ea95369d686bdc4b3d8c027e2b99cd (diff)
ksm: get_ksm_page locked
In some places where get_ksm_page() is used, we need the page to be locked. When KSM migration is fully enabled, we shall want that to make sure that the page just acquired cannot be migrated beneath us (raised page count is only effective when there is serialization to make sure migration notices). Whereas when navigating through the stable tree, we certainly do not want to lock each node (raised page count is enough to guarantee the memcmps, even if page is migrated to another node). Since we're about to add another use case, add the locked argument to get_ksm_page() now. Hmm, what's that rcu_read_lock() about? Complete misunderstanding, I really got the wrong end of the stick on that! There's a configuration in which page_cache_get_speculative() can do something cheaper than get_page_unless_zero(), relying on its caller's rcu_read_lock() to have disabled preemption for it. There's no need for rcu_read_lock() around get_page_unless_zero() (and mapping checks) here. Cut out that silliness before making this any harder to understand. Signed-off-by: Hugh Dickins <hughd@google.com> Cc: Rik van Riel <riel@redhat.com> Cc: Petr Holasek <pholasek@redhat.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Izik Eidus <izik.eidus@ravellosystems.com> Cc: Gerald Schaefer <gerald.schaefer@de.ibm.com> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/ksm.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/mm/ksm.c b/mm/ksm.c
index 70daa35266ef..e02430fb26f6 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -514,15 +514,14 @@ static void remove_node_from_stable_tree(struct stable_node *stable_node)
514 * but this is different - made simpler by ksm_thread_mutex being held, but 514 * but this is different - made simpler by ksm_thread_mutex being held, but
515 * interesting for assuming that no other use of the struct page could ever 515 * interesting for assuming that no other use of the struct page could ever
516 * put our expected_mapping into page->mapping (or a field of the union which 516 * put our expected_mapping into page->mapping (or a field of the union which
517 * coincides with page->mapping). The RCU calls are not for KSM at all, but 517 * coincides with page->mapping).
518 * to keep the page_count protocol described with page_cache_get_speculative.
519 * 518 *
520 * Note: it is possible that get_ksm_page() will return NULL one moment, 519 * Note: it is possible that get_ksm_page() will return NULL one moment,
521 * then page the next, if the page is in between page_freeze_refs() and 520 * then page the next, if the page is in between page_freeze_refs() and
522 * page_unfreeze_refs(): this shouldn't be a problem anywhere, the page 521 * page_unfreeze_refs(): this shouldn't be a problem anywhere, the page
523 * is on its way to being freed; but it is an anomaly to bear in mind. 522 * is on its way to being freed; but it is an anomaly to bear in mind.
524 */ 523 */
525static struct page *get_ksm_page(struct stable_node *stable_node) 524static struct page *get_ksm_page(struct stable_node *stable_node, bool locked)
526{ 525{
527 struct page *page; 526 struct page *page;
528 void *expected_mapping; 527 void *expected_mapping;
@@ -530,7 +529,6 @@ static struct page *get_ksm_page(struct stable_node *stable_node)
530 page = pfn_to_page(stable_node->kpfn); 529 page = pfn_to_page(stable_node->kpfn);
531 expected_mapping = (void *)stable_node + 530 expected_mapping = (void *)stable_node +
532 (PAGE_MAPPING_ANON | PAGE_MAPPING_KSM); 531 (PAGE_MAPPING_ANON | PAGE_MAPPING_KSM);
533 rcu_read_lock();
534 if (page->mapping != expected_mapping) 532 if (page->mapping != expected_mapping)
535 goto stale; 533 goto stale;
536 if (!get_page_unless_zero(page)) 534 if (!get_page_unless_zero(page))
@@ -539,10 +537,16 @@ static struct page *get_ksm_page(struct stable_node *stable_node)
539 put_page(page); 537 put_page(page);
540 goto stale; 538 goto stale;
541 } 539 }
542 rcu_read_unlock(); 540 if (locked) {
541 lock_page(page);
542 if (page->mapping != expected_mapping) {
543 unlock_page(page);
544 put_page(page);
545 goto stale;
546 }
547 }
543 return page; 548 return page;
544stale: 549stale:
545 rcu_read_unlock();
546 remove_node_from_stable_tree(stable_node); 550 remove_node_from_stable_tree(stable_node);
547 return NULL; 551 return NULL;
548} 552}
@@ -558,11 +562,10 @@ static void remove_rmap_item_from_tree(struct rmap_item *rmap_item)
558 struct page *page; 562 struct page *page;
559 563
560 stable_node = rmap_item->head; 564 stable_node = rmap_item->head;
561 page = get_ksm_page(stable_node); 565 page = get_ksm_page(stable_node, true);
562 if (!page) 566 if (!page)
563 goto out; 567 goto out;
564 568
565 lock_page(page);
566 hlist_del(&rmap_item->hlist); 569 hlist_del(&rmap_item->hlist);
567 unlock_page(page); 570 unlock_page(page);
568 put_page(page); 571 put_page(page);
@@ -1042,7 +1045,7 @@ static struct page *stable_tree_search(struct page *page)
1042 1045
1043 cond_resched(); 1046 cond_resched();
1044 stable_node = rb_entry(node, struct stable_node, node); 1047 stable_node = rb_entry(node, struct stable_node, node);
1045 tree_page = get_ksm_page(stable_node); 1048 tree_page = get_ksm_page(stable_node, false);
1046 if (!tree_page) 1049 if (!tree_page)
1047 return NULL; 1050 return NULL;
1048 1051
@@ -1086,7 +1089,7 @@ static struct stable_node *stable_tree_insert(struct page *kpage)
1086 1089
1087 cond_resched(); 1090 cond_resched();
1088 stable_node = rb_entry(*new, struct stable_node, node); 1091 stable_node = rb_entry(*new, struct stable_node, node);
1089 tree_page = get_ksm_page(stable_node); 1092 tree_page = get_ksm_page(stable_node, false);
1090 if (!tree_page) 1093 if (!tree_page)
1091 return NULL; 1094 return NULL;
1092 1095