Merge tag 'zstd-linus-v6.2' of https://github.com/terrelln/linux
[platform/kernel/linux-starfive.git] / mm / madvise.c
index d03e149..a56a6d1 100644 (file)
@@ -95,9 +95,6 @@ struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
 {
        mmap_assert_locked(vma->vm_mm);
 
-       if (vma->vm_file)
-               return NULL;
-
        return vma->anon_name;
 }
 
@@ -183,7 +180,7 @@ success:
         * vm_flags is protected by the mmap_lock held in write mode.
         */
        vma->vm_flags = new_flags;
-       if (!vma->vm_file) {
+       if (!vma->vm_file || vma_is_anon_shmem(vma)) {
                error = replace_anon_vma_name(vma, anon_name);
                if (error)
                        return error;
@@ -226,6 +223,7 @@ static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start,
                        put_page(page);
        }
        swap_read_unplug(splug);
+       cond_resched();
 
        return 0;
 }
@@ -321,6 +319,21 @@ static long madvise_willneed(struct vm_area_struct *vma,
        return 0;
 }
 
+static inline bool can_do_file_pageout(struct vm_area_struct *vma)
+{
+       if (!vma->vm_file)
+               return false;
+       /*
+        * paging out pagecache only for non-anonymous mappings that correspond
+        * to the files the calling process could (if tried) open for writing;
+        * otherwise we'd be including shared non-exclusive mappings, which
+        * opens a side channel.
+        */
+       return inode_owner_or_capable(&init_user_ns,
+                                     file_inode(vma->vm_file)) ||
+              file_permission(vma->vm_file, MAY_WRITE) == 0;
+}
+
 static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
                                unsigned long addr, unsigned long end,
                                struct mm_walk *walk)
@@ -334,10 +347,14 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
        spinlock_t *ptl;
        struct page *page = NULL;
        LIST_HEAD(page_list);
+       bool pageout_anon_only_filter;
 
        if (fatal_signal_pending(current))
                return -EINTR;
 
+       pageout_anon_only_filter = pageout && !vma_is_anonymous(vma) &&
+                                       !can_do_file_pageout(vma);
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
        if (pmd_trans_huge(*pmd)) {
                pmd_t orig_pmd;
@@ -364,6 +381,9 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
                if (page_mapcount(page) != 1)
                        goto huge_unlock;
 
+               if (pageout_anon_only_filter && !PageAnon(page))
+                       goto huge_unlock;
+
                if (next - addr != HPAGE_PMD_SIZE) {
                        int err;
 
@@ -432,6 +452,8 @@ regular_page:
                if (PageTransCompound(page)) {
                        if (page_mapcount(page) != 1)
                                break;
+                       if (pageout_anon_only_filter && !PageAnon(page))
+                               break;
                        get_page(page);
                        if (!trylock_page(page)) {
                                put_page(page);
@@ -459,6 +481,9 @@ regular_page:
                if (!PageLRU(page) || page_mapcount(page) != 1)
                        continue;
 
+               if (pageout_anon_only_filter && !PageAnon(page))
+                       continue;
+
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
 
                if (pte_young(ptent)) {
@@ -553,23 +578,6 @@ static void madvise_pageout_page_range(struct mmu_gather *tlb,
        tlb_end_vma(tlb, vma);
 }
 
-static inline bool can_do_pageout(struct vm_area_struct *vma)
-{
-       if (vma_is_anonymous(vma))
-               return true;
-       if (!vma->vm_file)
-               return false;
-       /*
-        * paging out pagecache only for non-anonymous mappings that correspond
-        * to the files the calling process could (if tried) open for writing;
-        * otherwise we'd be including shared non-exclusive mappings, which
-        * opens a side channel.
-        */
-       return inode_owner_or_capable(&init_user_ns,
-                                     file_inode(vma->vm_file)) ||
-              file_permission(vma->vm_file, MAY_WRITE) == 0;
-}
-
 static long madvise_pageout(struct vm_area_struct *vma,
                        struct vm_area_struct **prev,
                        unsigned long start_addr, unsigned long end_addr)
@@ -581,7 +589,14 @@ static long madvise_pageout(struct vm_area_struct *vma,
        if (!can_madv_lru_vma(vma))
                return -EINVAL;
 
-       if (!can_do_pageout(vma))
+       /*
+        * If the VMA belongs to a private file mapping, there can be private
+        * dirty pages which can be paged out if even this process is neither
+        * owner nor write capable of the file. We allow private file mappings
+        * further to pageout dirty anon pages.
+        */
+       if (!vma_is_anonymous(vma) && (!can_do_file_pageout(vma) &&
+                               (vma->vm_flags & VM_MAYSHARE)))
                return 0;
 
        lru_add_drain();
@@ -1273,7 +1288,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
        int error;
 
        /* Only anonymous mappings can be named */
-       if (vma->vm_file)
+       if (vma->vm_file && !vma_is_anon_shmem(vma))
                return -EBADF;
 
        error = madvise_update_vma(vma, prev, start, end, vma->vm_flags,