mm: introduce a common interface for balloon pages mobility
[platform/kernel/linux-arm64.git] / mm / rmap.c
index 7df7984..cf7e99a 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -56,6 +56,7 @@
 #include <linux/mmu_notifier.h>
 #include <linux/migrate.h>
 #include <linux/hugetlb.h>
+#include <linux/backing-dev.h>
 
 #include <asm/tlbflush.h>
 
@@ -561,6 +562,27 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
        return address;
 }
 
+pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd = NULL;
+
+       pgd = pgd_offset(mm, address);
+       if (!pgd_present(*pgd))
+               goto out;
+
+       pud = pud_offset(pgd, address);
+       if (!pud_present(*pud))
+               goto out;
+
+       pmd = pmd_offset(pud, address);
+       if (!pmd_present(*pmd))
+               pmd = NULL;
+out:
+       return pmd;
+}
+
 /*
  * Check that @page is mapped at @address into @mm.
  *
@@ -573,8 +595,6 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
 pte_t *__page_check_address(struct page *page, struct mm_struct *mm,
                          unsigned long address, spinlock_t **ptlp, int sync)
 {
-       pgd_t *pgd;
-       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        spinlock_t *ptl;
@@ -585,17 +605,10 @@ pte_t *__page_check_address(struct page *page, struct mm_struct *mm,
                goto check;
        }
 
-       pgd = pgd_offset(mm, address);
-       if (!pgd_present(*pgd))
+       pmd = mm_find_pmd(mm, address);
+       if (!pmd)
                return NULL;
 
-       pud = pud_offset(pgd, address);
-       if (!pud_present(*pud))
-               return NULL;
-
-       pmd = pmd_offset(pud, address);
-       if (!pmd_present(*pmd))
-               return NULL;
        if (pmd_trans_huge(*pmd))
                return NULL;
 
@@ -926,11 +939,8 @@ int page_mkclean(struct page *page)
 
        if (page_mapped(page)) {
                struct address_space *mapping = page_mapping(page);
-               if (mapping) {
+               if (mapping)
                        ret = page_mkclean_file(mapping, page);
-                       if (page_test_and_clear_dirty(page_to_pfn(page), 1))
-                               ret = 1;
-               }
        }
 
        return ret;
@@ -1116,6 +1126,7 @@ void page_add_file_rmap(struct page *page)
  */
 void page_remove_rmap(struct page *page)
 {
+       struct address_space *mapping = page_mapping(page);
        bool anon = PageAnon(page);
        bool locked;
        unsigned long flags;
@@ -1138,8 +1149,21 @@ void page_remove_rmap(struct page *page)
         * this if the page is anon, so about to be freed; but perhaps
         * not if it's in swapcache - there might be another pte slot
         * containing the swap entry, but page not yet written to swap.
+        *
+        * And we can skip it on file pages, so long as the filesystem
+        * participates in dirty tracking (note that this is not only an
+        * optimization but also solves problems caused by dirty flag in
+        * storage key getting set by a write from inside kernel); but need to
+        * catch shm and tmpfs and ramfs pages which have been modified since
+        * creation by read fault.
+        *
+        * Note that mapping must be decided above, before decrementing
+        * mapcount (which luckily provides a barrier): once page is unmapped,
+        * it could be truncated and page->mapping reset to NULL at any moment.
+        * Note also that we are relying on page_mapping(page) to set mapping
+        * to &swapper_space when PageSwapCache(page).
         */
-       if ((!anon || PageSwapCache(page)) &&
+       if (mapping && !mapping_cap_account_dirty(mapping) &&
            page_test_and_clear_dirty(page_to_pfn(page), 1))
                set_page_dirty(page);
        /*
@@ -1335,8 +1359,6 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
                struct vm_area_struct *vma, struct page *check_page)
 {
        struct mm_struct *mm = vma->vm_mm;
-       pgd_t *pgd;
-       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        pte_t pteval;
@@ -1356,16 +1378,8 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
        if (end > vma->vm_end)
                end = vma->vm_end;
 
-       pgd = pgd_offset(mm, address);
-       if (!pgd_present(*pgd))
-               return ret;
-
-       pud = pud_offset(pgd, address);
-       if (!pud_present(*pud))
-               return ret;
-
-       pmd = pmd_offset(pud, address);
-       if (!pmd_present(*pmd))
+       pmd = mm_find_pmd(mm, address);
+       if (!pmd)
                return ret;
 
        mmun_start = address;