summaryrefslogtreecommitdiff
path: root/mm/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory.c')
-rw-r--r--mm/memory.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/mm/memory.c b/mm/memory.c
index 09a57fe6ae01..ccb04d3f9bab 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2399,7 +2399,10 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
* Take out anonymous pages first, anonymous shared vmas are
* not dirty accountable.
*/
- if (PageAnon(old_page) && !PageKsm(old_page)) {
+ if (PageAnon(old_page)) {
+ if (PageKsm(old_page) && (PageSwapCache(old_page) ||
+ page_count(old_page) != 1))
+ goto copy;
if (!trylock_page(old_page)) {
page_cache_get(old_page);
pte_unmap_unlock(page_table, ptl);
@@ -2414,6 +2417,16 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
}
page_cache_release(old_page);
}
+ if (PageKsm(old_page)) {
+ bool reused = reuse_ksm_page(old_page, vma,
+ address);
+ unlock_page(old_page);
+ if (!reused)
+ goto copy;
+ wp_page_reuse(mm, vma, address, page_table, ptl,
+ orig_pte, old_page, 0, 0);
+ return VM_FAULT_WRITE;
+ }
if (reuse_swap_page(old_page)) {
/*
* The page is all ours. Move it to our anon_vma so
@@ -2431,7 +2444,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
return wp_page_shared(mm, vma, address, page_table, pmd,
ptl, orig_pte, old_page);
}
-
+copy:
/*
* Ok, we need to copy. Oh, well..
*/