Merge 5.18-rc5 into driver-core-next
[linux-2.6-microblaze.git] / mm / madvise.c
index 38d0f51..1873616 100644 (file)
@@ -52,6 +52,7 @@ static int madvise_need_mmap_write(int behavior)
        case MADV_REMOVE:
        case MADV_WILLNEED:
        case MADV_DONTNEED:
+       case MADV_DONTNEED_LOCKED:
        case MADV_COLD:
        case MADV_PAGEOUT:
        case MADV_FREE:
@@ -502,6 +503,11 @@ static void madvise_cold_page_range(struct mmu_gather *tlb,
        tlb_end_vma(tlb, vma);
 }
 
+static inline bool can_madv_lru_vma(struct vm_area_struct *vma)
+{
+       return !(vma->vm_flags & (VM_LOCKED|VM_PFNMAP|VM_HUGETLB));
+}
+
 static long madvise_cold(struct vm_area_struct *vma,
                        struct vm_area_struct **prev,
                        unsigned long start_addr, unsigned long end_addr)
@@ -772,6 +778,29 @@ static long madvise_dontneed_single_vma(struct vm_area_struct *vma,
        return 0;
 }
 
+static bool madvise_dontneed_free_valid_vma(struct vm_area_struct *vma,
+                                           unsigned long start,
+                                           unsigned long *end,
+                                           int behavior)
+{
+       if (!is_vm_hugetlb_page(vma)) {
+               unsigned int forbidden = VM_PFNMAP;
+
+               if (behavior != MADV_DONTNEED_LOCKED)
+                       forbidden |= VM_LOCKED;
+
+               return !(vma->vm_flags & forbidden);
+       }
+
+       if (behavior != MADV_DONTNEED && behavior != MADV_DONTNEED_LOCKED)
+               return false;
+       if (start & ~huge_page_mask(hstate_vma(vma)))
+               return false;
+
+       *end = ALIGN(*end, huge_page_size(hstate_vma(vma)));
+       return true;
+}
+
 static long madvise_dontneed_free(struct vm_area_struct *vma,
                                  struct vm_area_struct **prev,
                                  unsigned long start, unsigned long end,
@@ -780,7 +809,7 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,
        struct mm_struct *mm = vma->vm_mm;
 
        *prev = vma;
-       if (!can_madv_lru_vma(vma))
+       if (!madvise_dontneed_free_valid_vma(vma, start, &end, behavior))
                return -EINVAL;
 
        if (!userfaultfd_remove(vma, start, end)) {
@@ -802,7 +831,12 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,
                         */
                        return -ENOMEM;
                }
-               if (!can_madv_lru_vma(vma))
+               /*
+                * Potential end adjustment for hugetlb vma is OK as
+                * the check below keeps end within vma.
+                */
+               if (!madvise_dontneed_free_valid_vma(vma, start, &end,
+                                                    behavior))
                        return -EINVAL;
                if (end > vma->vm_end) {
                        /*
@@ -822,7 +856,7 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,
                VM_WARN_ON(start >= end);
        }
 
-       if (behavior == MADV_DONTNEED)
+       if (behavior == MADV_DONTNEED || behavior == MADV_DONTNEED_LOCKED)
                return madvise_dontneed_single_vma(vma, start, end);
        else if (behavior == MADV_FREE)
                return madvise_free_single_vma(vma, start, end);
@@ -849,8 +883,8 @@ static long madvise_populate(struct vm_area_struct *vma,
                 * our VMA might have been split.
                 */
                if (!vma || start >= vma->vm_end) {
-                       vma = find_vma(mm, start);
-                       if (!vma || start < vma->vm_start)
+                       vma = vma_lookup(mm, start);
+                       if (!vma)
                                return -ENOMEM;
                }
 
@@ -961,6 +995,7 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
                return madvise_pageout(vma, prev, start, end);
        case MADV_FREE:
        case MADV_DONTNEED:
+       case MADV_DONTNEED_LOCKED:
                return madvise_dontneed_free(vma, prev, start, end, behavior);
        case MADV_POPULATE_READ:
        case MADV_POPULATE_WRITE:
@@ -1067,6 +1102,8 @@ static int madvise_inject_error(int behavior,
                        pr_info("Injecting memory failure for pfn %#lx at process virtual address %#lx\n",
                                 pfn, start);
                        ret = memory_failure(pfn, MF_COUNT_INCREASED);
+                       if (ret == -EOPNOTSUPP)
+                               ret = 0;
                }
 
                if (ret)
@@ -1089,6 +1126,7 @@ madvise_behavior_valid(int behavior)
        case MADV_REMOVE:
        case MADV_WILLNEED:
        case MADV_DONTNEED:
+       case MADV_DONTNEED_LOCKED:
        case MADV_FREE:
        case MADV_COLD:
        case MADV_PAGEOUT:
@@ -1433,8 +1471,7 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec,
                iov_iter_advance(&iter, iovec.iov_len);
        }
 
-       if (ret == 0)
-               ret = total_len - iov_iter_count(&iter);
+       ret = (total_len - iov_iter_count(&iter)) ? : ret;
 
 release_mm:
        mmput(mm);