]> git.ipfire.org Git - people/ms/linux.git/blobdiff - mm/madvise.c
mm: enable MADV_DONTNEED for hugetlb mappings
[people/ms/linux.git] / mm / madvise.c
index 39b712fd83000361c9f6e1d4d377514c27d04eea..2e6213664c5232266451068ef7f310dd7442874e 100644 (file)
@@ -502,9 +502,14 @@ static void madvise_cold_page_range(struct mmu_gather *tlb,
        tlb_end_vma(tlb, vma);
 }
 
+static inline bool can_madv_lru_non_huge_vma(struct vm_area_struct *vma)
+{
+       return !(vma->vm_flags & (VM_LOCKED|VM_PFNMAP));
+}
+
 static inline bool can_madv_lru_vma(struct vm_area_struct *vma)
 {
-       return !(vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP));
+       return can_madv_lru_non_huge_vma(vma) && !is_vm_hugetlb_page(vma);
 }
 
 static long madvise_cold(struct vm_area_struct *vma,
@@ -777,6 +782,23 @@ 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))
+               return can_madv_lru_non_huge_vma(vma);
+
+       if (behavior != MADV_DONTNEED)
+               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,
@@ -785,7 +807,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)) {
@@ -807,7 +829,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) {
                        /*