Merge tag 'asoc-fix-v5.14-rc4' of https://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / mm / madvise.c
index 63e489e..6d3d348 100644 (file)
@@ -53,6 +53,8 @@ static int madvise_need_mmap_write(int behavior)
        case MADV_COLD:
        case MADV_PAGEOUT:
        case MADV_FREE:
+       case MADV_POPULATE_READ:
+       case MADV_POPULATE_WRITE:
                return 0;
        default:
                /* be safe, default to 1. list exceptions explicitly */
@@ -822,6 +824,61 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,
                return -EINVAL;
 }
 
+static long madvise_populate(struct vm_area_struct *vma,
+                            struct vm_area_struct **prev,
+                            unsigned long start, unsigned long end,
+                            int behavior)
+{
+       const bool write = behavior == MADV_POPULATE_WRITE;
+       struct mm_struct *mm = vma->vm_mm;
+       unsigned long tmp_end;
+       int locked = 1;
+       long pages;
+
+       *prev = vma;
+
+       while (start < end) {
+               /*
+                * We might have temporarily dropped the lock. For example,
+                * our VMA might have been split.
+                */
+               if (!vma || start >= vma->vm_end) {
+                       vma = find_vma(mm, start);
+                       if (!vma || start < vma->vm_start)
+                               return -ENOMEM;
+               }
+
+               tmp_end = min_t(unsigned long, end, vma->vm_end);
+               /* Populate (prefault) page tables readable/writable. */
+               pages = faultin_vma_page_range(vma, start, tmp_end, write,
+                                              &locked);
+               if (!locked) {
+                       mmap_read_lock(mm);
+                       locked = 1;
+                       *prev = NULL;
+                       vma = NULL;
+               }
+               if (pages < 0) {
+                       switch (pages) {
+                       case -EINTR:
+                               return -EINTR;
+                       case -EFAULT: /* Incompatible mappings / permissions. */
+                               return -EINVAL;
+                       case -EHWPOISON:
+                               return -EHWPOISON;
+                       default:
+                               pr_warn_once("%s: unhandled return value: %ld\n",
+                                            __func__, pages);
+                               fallthrough;
+                       case -ENOMEM:
+                               return -ENOMEM;
+                       }
+               }
+               start += pages * PAGE_SIZE;
+       }
+       return 0;
+}
+
 /*
  * Application wants to free up the pages and associated backing store.
  * This is effectively punching a hole into the middle of a file.
@@ -935,6 +992,9 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
        case MADV_FREE:
        case MADV_DONTNEED:
                return madvise_dontneed_free(vma, prev, start, end, behavior);
+       case MADV_POPULATE_READ:
+       case MADV_POPULATE_WRITE:
+               return madvise_populate(vma, prev, start, end, behavior);
        default:
                return madvise_behavior(vma, prev, start, end, behavior);
        }
@@ -955,6 +1015,8 @@ madvise_behavior_valid(int behavior)
        case MADV_FREE:
        case MADV_COLD:
        case MADV_PAGEOUT:
+       case MADV_POPULATE_READ:
+       case MADV_POPULATE_WRITE:
 #ifdef CONFIG_KSM
        case MADV_MERGEABLE:
        case MADV_UNMERGEABLE:
@@ -1042,6 +1104,10 @@ process_madvise_behavior_valid(int behavior)
  *             easily if memory pressure happens.
  *  MADV_PAGEOUT - the application is not expected to use this memory soon,
  *             page out the pages in this range immediately.
+ *  MADV_POPULATE_READ - populate (prefault) page tables readable by
+ *             triggering read faults if required
+ *  MADV_POPULATE_WRITE - populate (prefault) page tables writable by
+ *             triggering write faults if required
  *
  * return values:
  *  zero    - success