diff options
Diffstat (limited to 'mm/ksm.c')
-rw-r--r-- | mm/ksm.c | 23 |
1 files changed, 13 insertions, 10 deletions
@@ -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 | */ |
525 | static struct page *get_ksm_page(struct stable_node *stable_node) | 524 | static 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; |
544 | stale: | 549 | stale: |
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 | ||