swap: Add try_to_unuse_page_entry()
Subsystems (4)
PATCH 2/9 swap: Add try_to_unuse_page_entry()
Add try_to_unuse_page_entry() which can be used to unuse page entries.
This needs try_to_unuse_anon() which is also added, similar to try_to_unmap_anon().
Originally based on a patch by Nick Piggin from LKML with changes of my own after hints from Hugh Dickins.
Signed-off-by Richard Purdie <[email protected]>
--- include/linux/rmap.h | 6 +++++ include/linux/swap.h | 1 mm/rmap.c | 2 - mm/swapfile.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-)
mm/swapfile.c +55 -0
@@ -646,6 +646,61 @@ static int unuse_mm(struct mm_struct *mmreturn 0 ; } +static int try_to_unuse_anon (swp_entry_t entry,struct page *page) +{ +struct anon_vma *anon_vma; +struct vm_area_struct *vma; + + anon_vma =page_lock_anon_vma (page); +if (!anon_vma) +return 0 ; + +list_for_each_entry (vma, &anon_vma->head, anon_vma_node) { +if (unuse_vma (vma, entry, page)) +break ; + } +spin_unlock (&anon_vma->lock); +return 0 ; +} + + +void try_to_unuse_page_entry (struct page *page) +{ +struct swap_info_struct *si; +unsigned short *swap_map; +swp_entry_t entry; + +BUG_ON (!PageLocked (page)); +BUG_ON (!PageSwapCache (page)); +BUG_ON (PageWriteback (page)); +BUG_ON (PagePrivate (page)); + + entry.val =page_private (page); + si =swap_info_get (entry); +if (!si) { +WARN_ON (1 ); +return ; + } + swap_map = &si->swap_map[swp_offset (entry)]; +spin_unlock (&swap_lock); + +BUG_ON (*swap_map ==SWAP_MAP_BAD ); + +if (!shmem_unuse (entry, page)) { +try_to_unuse_anon (entry, page); +delete_from_swap_cache (page); + }else if (PageSwapCache (page)) { +/* +* shmem_unuse deleted a swappage from the swap cache, but the +* move to filepage failed so it left swappage in cache and +* lowered its swap count to pass quickly through the loops in +* try_to_unuse(). We must reincrement the count to try again +* later (ick). +*/ +swap_duplicate (entry); + } +} +/* * Scan swap_map from current position to next entry still in use. * Recycle to start on reaching the end, returning 0 when empty.
include/linux/rmap.h +6 -0
@@ -104,6 +104,11 @@ pte_t *page_check_address(struct page *,unsigned long page_address_in_vma (struct page *,struct vm_area_struct *);/* +* Used by try_to_unuse_anon() and try_to_unmap_anon() +*/ +struct anon_vma *page_lock_anon_vma (struct page *page); + +/* * Cleans the PTEs of shared mappings. * (and since clean PTEs should also be readonly, write protects them too) *
@@ -125,6 +130,7 @@ static inline int page_mkclean(struct pa return 0; } +#define page_lock_anon_vma (page) (0)#endif /* CONFIG_MMU */
mm/rmap.c +1 -1
@@ -181,7 +181,7 @@ void __init anon_vma_init(void)* Getting a lock on a stable anon_vma from a page off the LRU is * tricky: page_lock_anon_vma rely on RCU to guard against the races. */ -static struct anon_vma *page_lock_anon_vma (struct page *page) +struct anon_vma *page_lock_anon_vma (struct page *page) {struct anon_vma *anon_vma =NULL ;unsigned long anon_mapping;
include/linux/swap.h +1 -0
@@ -254,6 +254,7 @@ extern sector_t swapdev_block(int, pgoffextern struct swap_info_struct *get_swap_info_struct (unsigned );extern int can_share_swap_page (struct page *);extern int remove_exclusive_swap_page (struct page *); +extern void try_to_unuse_page_entry (struct page *page);struct backing_dev_info ;extern spinlock_t swap_lock;