diff options
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 17 |
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.. */ |