summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/rmap.h1
-rw-r--r--include/linux/swap.h1
-rw-r--r--mm/rmap.c29
-rw-r--r--mm/swapfile.c9
-rw-r--r--mm/vmscan.c9
5 files changed, 49 insertions, 0 deletions
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 0f1ea2d6ed86..d6b9bcd1384c 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -92,6 +92,7 @@ static inline void page_dup_rmap(struct page *page)
*/
int page_referenced(struct page *, int is_locked);
int try_to_unmap(struct page *, int ignore_refs);
+void remove_from_swap(struct page *page);
/*
* Called from mm/filemap_xip.c to unmap empty zero page
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d359fc022433..229b6d04b4b6 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -248,6 +248,7 @@ extern int remove_exclusive_swap_page(struct page *);
struct backing_dev_info;
extern spinlock_t swap_lock;
+extern int remove_vma_swap(struct vm_area_struct *vma, struct page *page);
/* linux/mm/thrash.c */
extern struct mm_struct * swap_token_mm;
diff --git a/mm/rmap.c b/mm/rmap.c
index 13fad5fcdf79..f4b91d7aa5cf 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -206,6 +206,35 @@ out:
return anon_vma;
}
+#ifdef CONFIG_MIGRATION
+/*
+ * Remove an anonymous page from swap replacing the swap pte's
+ * through real pte's pointing to valid pages and then releasing
+ * the page from the swap cache.
+ *
+ * Must hold page lock on page.
+ */
+void remove_from_swap(struct page *page)
+{
+ struct anon_vma *anon_vma;
+ struct vm_area_struct *vma;
+
+ if (!PageAnon(page) || !PageSwapCache(page))
+ return;
+
+ anon_vma = page_lock_anon_vma(page);
+ if (!anon_vma)
+ return;
+
+ list_for_each_entry(vma, &anon_vma->head, anon_vma_node)
+ remove_vma_swap(vma, page);
+
+ spin_unlock(&anon_vma->lock);
+
+ delete_from_swap_cache(page);
+}
+#endif
+
/*
* At what user virtual address is page expected in vma?
*/
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 9678182e0eef..1f9cf0d073b8 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -554,6 +554,15 @@ static int unuse_mm(struct mm_struct *mm,
return 0;
}
+#ifdef CONFIG_MIGRATION
+int remove_vma_swap(struct vm_area_struct *vma, struct page *page)
+{
+ swp_entry_t entry = { .val = page_private(page) };
+
+ return unuse_vma(vma, entry, page);
+}
+#endif
+
/*
* Scan swap_map from current position to next entry still in use.
* Recycle to start on reaching the end, returning 0 when empty.
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 8f326ce2b690..5e98b86feb74 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -804,6 +804,15 @@ int migrate_page(struct page *newpage, struct page *page)
migrate_page_copy(newpage, page);
+ /*
+ * Remove auxiliary swap entries and replace
+ * them with real ptes.
+ *
+ * Note that a real pte entry will allow processes that are not
+ * waiting on the page lock to use the new page via the page tables
+ * before the new page is unlocked.
+ */
+ remove_from_swap(newpage);
return 0;
}