diff options
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 107 |
1 files changed, 45 insertions, 62 deletions
@@ -103,7 +103,7 @@ int anon_vma_prepare(struct vm_area_struct *vma) | |||
103 | spin_lock(&mm->page_table_lock); | 103 | spin_lock(&mm->page_table_lock); |
104 | if (likely(!vma->anon_vma)) { | 104 | if (likely(!vma->anon_vma)) { |
105 | vma->anon_vma = anon_vma; | 105 | vma->anon_vma = anon_vma; |
106 | list_add(&vma->anon_vma_node, &anon_vma->head); | 106 | list_add_tail(&vma->anon_vma_node, &anon_vma->head); |
107 | allocated = NULL; | 107 | allocated = NULL; |
108 | } | 108 | } |
109 | spin_unlock(&mm->page_table_lock); | 109 | spin_unlock(&mm->page_table_lock); |
@@ -127,7 +127,7 @@ void __anon_vma_link(struct vm_area_struct *vma) | |||
127 | struct anon_vma *anon_vma = vma->anon_vma; | 127 | struct anon_vma *anon_vma = vma->anon_vma; |
128 | 128 | ||
129 | if (anon_vma) { | 129 | if (anon_vma) { |
130 | list_add(&vma->anon_vma_node, &anon_vma->head); | 130 | list_add_tail(&vma->anon_vma_node, &anon_vma->head); |
131 | validate_anon_vma(vma); | 131 | validate_anon_vma(vma); |
132 | } | 132 | } |
133 | } | 133 | } |
@@ -138,7 +138,7 @@ void anon_vma_link(struct vm_area_struct *vma) | |||
138 | 138 | ||
139 | if (anon_vma) { | 139 | if (anon_vma) { |
140 | spin_lock(&anon_vma->lock); | 140 | spin_lock(&anon_vma->lock); |
141 | list_add(&vma->anon_vma_node, &anon_vma->head); | 141 | list_add_tail(&vma->anon_vma_node, &anon_vma->head); |
142 | validate_anon_vma(vma); | 142 | validate_anon_vma(vma); |
143 | spin_unlock(&anon_vma->lock); | 143 | spin_unlock(&anon_vma->lock); |
144 | } | 144 | } |
@@ -205,44 +205,6 @@ out: | |||
205 | return anon_vma; | 205 | return anon_vma; |
206 | } | 206 | } |
207 | 207 | ||
208 | #ifdef CONFIG_MIGRATION | ||
209 | /* | ||
210 | * Remove an anonymous page from swap replacing the swap pte's | ||
211 | * through real pte's pointing to valid pages and then releasing | ||
212 | * the page from the swap cache. | ||
213 | * | ||
214 | * Must hold page lock on page and mmap_sem of one vma that contains | ||
215 | * the page. | ||
216 | */ | ||
217 | void remove_from_swap(struct page *page) | ||
218 | { | ||
219 | struct anon_vma *anon_vma; | ||
220 | struct vm_area_struct *vma; | ||
221 | unsigned long mapping; | ||
222 | |||
223 | if (!PageSwapCache(page)) | ||
224 | return; | ||
225 | |||
226 | mapping = (unsigned long)page->mapping; | ||
227 | |||
228 | if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0) | ||
229 | return; | ||
230 | |||
231 | /* | ||
232 | * We hold the mmap_sem lock. So no need to call page_lock_anon_vma. | ||
233 | */ | ||
234 | anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON); | ||
235 | spin_lock(&anon_vma->lock); | ||
236 | |||
237 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) | ||
238 | remove_vma_swap(vma, page); | ||
239 | |||
240 | spin_unlock(&anon_vma->lock); | ||
241 | delete_from_swap_cache(page); | ||
242 | } | ||
243 | EXPORT_SYMBOL(remove_from_swap); | ||
244 | #endif | ||
245 | |||
246 | /* | 208 | /* |
247 | * At what user virtual address is page expected in vma? | 209 | * At what user virtual address is page expected in vma? |
248 | */ | 210 | */ |
@@ -578,7 +540,7 @@ void page_remove_rmap(struct page *page) | |||
578 | * repeatedly from either try_to_unmap_anon or try_to_unmap_file. | 540 | * repeatedly from either try_to_unmap_anon or try_to_unmap_file. |
579 | */ | 541 | */ |
580 | static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | 542 | static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, |
581 | int ignore_refs) | 543 | int migration) |
582 | { | 544 | { |
583 | struct mm_struct *mm = vma->vm_mm; | 545 | struct mm_struct *mm = vma->vm_mm; |
584 | unsigned long address; | 546 | unsigned long address; |
@@ -602,7 +564,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | |||
602 | */ | 564 | */ |
603 | if ((vma->vm_flags & VM_LOCKED) || | 565 | if ((vma->vm_flags & VM_LOCKED) || |
604 | (ptep_clear_flush_young(vma, address, pte) | 566 | (ptep_clear_flush_young(vma, address, pte) |
605 | && !ignore_refs)) { | 567 | && !migration)) { |
606 | ret = SWAP_FAIL; | 568 | ret = SWAP_FAIL; |
607 | goto out_unmap; | 569 | goto out_unmap; |
608 | } | 570 | } |
@@ -620,24 +582,45 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | |||
620 | 582 | ||
621 | if (PageAnon(page)) { | 583 | if (PageAnon(page)) { |
622 | swp_entry_t entry = { .val = page_private(page) }; | 584 | swp_entry_t entry = { .val = page_private(page) }; |
623 | /* | 585 | |
624 | * Store the swap location in the pte. | 586 | if (PageSwapCache(page)) { |
625 | * See handle_pte_fault() ... | 587 | /* |
626 | */ | 588 | * Store the swap location in the pte. |
627 | BUG_ON(!PageSwapCache(page)); | 589 | * See handle_pte_fault() ... |
628 | swap_duplicate(entry); | 590 | */ |
629 | if (list_empty(&mm->mmlist)) { | 591 | swap_duplicate(entry); |
630 | spin_lock(&mmlist_lock); | 592 | if (list_empty(&mm->mmlist)) { |
631 | if (list_empty(&mm->mmlist)) | 593 | spin_lock(&mmlist_lock); |
632 | list_add(&mm->mmlist, &init_mm.mmlist); | 594 | if (list_empty(&mm->mmlist)) |
633 | spin_unlock(&mmlist_lock); | 595 | list_add(&mm->mmlist, &init_mm.mmlist); |
596 | spin_unlock(&mmlist_lock); | ||
597 | } | ||
598 | dec_mm_counter(mm, anon_rss); | ||
599 | #ifdef CONFIG_MIGRATION | ||
600 | } else { | ||
601 | /* | ||
602 | * Store the pfn of the page in a special migration | ||
603 | * pte. do_swap_page() will wait until the migration | ||
604 | * pte is removed and then restart fault handling. | ||
605 | */ | ||
606 | BUG_ON(!migration); | ||
607 | entry = make_migration_entry(page, pte_write(pteval)); | ||
608 | #endif | ||
634 | } | 609 | } |
635 | set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); | 610 | set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); |
636 | BUG_ON(pte_file(*pte)); | 611 | BUG_ON(pte_file(*pte)); |
637 | dec_mm_counter(mm, anon_rss); | ||
638 | } else | 612 | } else |
613 | #ifdef CONFIG_MIGRATION | ||
614 | if (migration) { | ||
615 | /* Establish migration entry for a file page */ | ||
616 | swp_entry_t entry; | ||
617 | entry = make_migration_entry(page, pte_write(pteval)); | ||
618 | set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); | ||
619 | } else | ||
620 | #endif | ||
639 | dec_mm_counter(mm, file_rss); | 621 | dec_mm_counter(mm, file_rss); |
640 | 622 | ||
623 | |||
641 | page_remove_rmap(page); | 624 | page_remove_rmap(page); |
642 | page_cache_release(page); | 625 | page_cache_release(page); |
643 | 626 | ||
@@ -736,7 +719,7 @@ static void try_to_unmap_cluster(unsigned long cursor, | |||
736 | pte_unmap_unlock(pte - 1, ptl); | 719 | pte_unmap_unlock(pte - 1, ptl); |
737 | } | 720 | } |
738 | 721 | ||
739 | static int try_to_unmap_anon(struct page *page, int ignore_refs) | 722 | static int try_to_unmap_anon(struct page *page, int migration) |
740 | { | 723 | { |
741 | struct anon_vma *anon_vma; | 724 | struct anon_vma *anon_vma; |
742 | struct vm_area_struct *vma; | 725 | struct vm_area_struct *vma; |
@@ -747,7 +730,7 @@ static int try_to_unmap_anon(struct page *page, int ignore_refs) | |||
747 | return ret; | 730 | return ret; |
748 | 731 | ||
749 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) { | 732 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) { |
750 | ret = try_to_unmap_one(page, vma, ignore_refs); | 733 | ret = try_to_unmap_one(page, vma, migration); |
751 | if (ret == SWAP_FAIL || !page_mapped(page)) | 734 | if (ret == SWAP_FAIL || !page_mapped(page)) |
752 | break; | 735 | break; |
753 | } | 736 | } |
@@ -764,7 +747,7 @@ static int try_to_unmap_anon(struct page *page, int ignore_refs) | |||
764 | * | 747 | * |
765 | * This function is only called from try_to_unmap for object-based pages. | 748 | * This function is only called from try_to_unmap for object-based pages. |
766 | */ | 749 | */ |
767 | static int try_to_unmap_file(struct page *page, int ignore_refs) | 750 | static int try_to_unmap_file(struct page *page, int migration) |
768 | { | 751 | { |
769 | struct address_space *mapping = page->mapping; | 752 | struct address_space *mapping = page->mapping; |
770 | pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); | 753 | pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); |
@@ -778,7 +761,7 @@ static int try_to_unmap_file(struct page *page, int ignore_refs) | |||
778 | 761 | ||
779 | spin_lock(&mapping->i_mmap_lock); | 762 | spin_lock(&mapping->i_mmap_lock); |
780 | vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { | 763 | vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { |
781 | ret = try_to_unmap_one(page, vma, ignore_refs); | 764 | ret = try_to_unmap_one(page, vma, migration); |
782 | if (ret == SWAP_FAIL || !page_mapped(page)) | 765 | if (ret == SWAP_FAIL || !page_mapped(page)) |
783 | goto out; | 766 | goto out; |
784 | } | 767 | } |
@@ -863,16 +846,16 @@ out: | |||
863 | * SWAP_AGAIN - we missed a mapping, try again later | 846 | * SWAP_AGAIN - we missed a mapping, try again later |
864 | * SWAP_FAIL - the page is unswappable | 847 | * SWAP_FAIL - the page is unswappable |
865 | */ | 848 | */ |
866 | int try_to_unmap(struct page *page, int ignore_refs) | 849 | int try_to_unmap(struct page *page, int migration) |
867 | { | 850 | { |
868 | int ret; | 851 | int ret; |
869 | 852 | ||
870 | BUG_ON(!PageLocked(page)); | 853 | BUG_ON(!PageLocked(page)); |
871 | 854 | ||
872 | if (PageAnon(page)) | 855 | if (PageAnon(page)) |
873 | ret = try_to_unmap_anon(page, ignore_refs); | 856 | ret = try_to_unmap_anon(page, migration); |
874 | else | 857 | else |
875 | ret = try_to_unmap_file(page, ignore_refs); | 858 | ret = try_to_unmap_file(page, migration); |
876 | 859 | ||
877 | if (!page_mapped(page)) | 860 | if (!page_mapped(page)) |
878 | ret = SWAP_SUCCESS; | 861 | ret = SWAP_SUCCESS; |