We have now made it such that every driver which sets VMA_IO_BIT marks it
as kernel-owned.

However, vma_flags_is_kernel_owned() currently checks for VMA_IO_BIT. This
was a product of drivers previously marking a range as kernel-owned by
setting VMA_IO_BIT alone.

Fix this by removing the VMA_IO_BIT check in vma_flags_is_kernel_owned(),
and update mmap_validate_vma_flags() to use vma_flags_is_kernel_owned()
rather than open-coding the VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT check.

This change means that vma[_flags]_can_merge() doesn't check VMA_IO_BIT any
longer (which is now redundant) as it calls vma_flags_is_kernel_owned().

Now that the predicate means precisely VMA_PFNMAP_BIT or VMA_MIXEDMAP_BIT,
also use it at the other sites which open-code that pair, so the intent is
stated rather than the flags, with no functional change:

zap_special_vma_range() only zaps kernel-owned mappings, as drivers use it
to tear down ranges they established themselves.

The mprotect() arch PFN modification check applies to kernel-owned
mappings, which may map PFNs without struct pages.

NUMA balancing skips VM_MIXEDMAP mappings having already excluded VM_IO
and VM_PFNMAP mappings via vma_migratable(), so it skips exactly the
kernel-owned mappings - say so.

Finally, update the VMA userland merge 'special' flag tests to no longer
assert that VMA_IO_BIT prevents merge as VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT
now suffices.

Signed-off-by: Lorenzo Stoakes (ARM) <[email protected]>
---
 include/linux/mm.h              |  3 +--
 kernel/sched/fair.c             |  2 +-
 mm/memory.c                     |  6 +++---
 mm/mprotect.c                   |  3 +--
 mm/vma.c                        |  2 +-
 tools/testing/vma/include/dup.h |  3 +--
 tools/testing/vma/tests/merge.c | 10 ++--------
 7 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index ca598e5f9715..4b6aa0b47b00 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1630,8 +1630,7 @@ static inline bool vma_is_shared_maywrite(const struct 
vm_area_struct *vma)
  */
 static inline bool vma_flags_is_kernel_owned(const vma_flags_t *flags)
 {
-       return vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT,
-                                 VMA_IO_BIT);
+       return vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT);
 }
 
 /**
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 8dff37059faf..a71f0ab79bcd 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4212,7 +4212,7 @@ static void task_numa_work(struct callback_head *work)
 
        for (; vma; vma = vma_next(&vmi)) {
                if (!vma_migratable(vma) || !vma_policy_mof(vma) ||
-                       is_vm_hugetlb_page(vma) || (vma->vm_flags & 
VM_MIXEDMAP)) {
+                       is_vm_hugetlb_page(vma) || vma_is_kernel_owned(vma)) {
                        trace_sched_skip_vma_numa(mm, vma, 
NUMAB_SKIP_UNSUITABLE);
                        continue;
                }
diff --git a/mm/memory.c b/mm/memory.c
index 42f084517247..38fe455dc70c 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2343,19 +2343,19 @@ void zap_vma_range(struct vm_area_struct *vma, unsigned 
long address,
 }
 
 /**
- * zap_special_vma_range - zap all page table entries in a special vma range
+ * zap_special_vma_range - zap all page table entries in a kernel-owned VMA
  * @vma: the vma covering the range to zap
  * @address: starting address of the range to zap
  * @size: number of bytes to zap
  *
  * This function does nothing when the provided address range is not fully
- * contained in @vma, or when the @vma is not VM_PFNMAP or VM_MIXEDMAP.
+ * contained in @vma, or when @vma is not kernel-owned.
  */
 void zap_special_vma_range(struct vm_area_struct *vma, unsigned long address,
                unsigned long size)
 {
        if (!range_in_vma(vma, address, address + size) ||
-          !(vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP)))
+          !vma_is_kernel_owned(vma))
                return;
 
        zap_vma_range(vma, address, size);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 2888ee638d87..fe32fd87cf5c 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -783,8 +783,7 @@ mprotect_fixup(struct vma_iterator *vmi, struct mmu_gather 
*tlb,
         * uncommon case, so doesn't need to be very optimized.
         */
        if (arch_has_pfn_modify_check() &&
-           vma_flags_test_any(&old_vma_flags, VMA_PFNMAP_BIT,
-                              VMA_MIXEDMAP_BIT) &&
+           vma_flags_is_kernel_owned(&old_vma_flags) &&
            !vma_flags_test_any_mask(&new_vma_flags, VMA_ACCESS_FLAGS)) {
                pgprot_t new_pgprot = vm_get_page_prot(newflags);
 
diff --git a/mm/vma.c b/mm/vma.c
index fa429771bea8..54e5f4bbd8af 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -2787,7 +2787,7 @@ static int mmap_validate_vma_flags(const vma_flags_t 
*flags)
                return -EINVAL;
 #endif
 
-       if (!vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT)) {
+       if (!vma_flags_is_kernel_owned(flags)) {
                /* Only kernel-owned mappings may set VMA_IO_BIT. */
                if (WARN_ON_ONCE(vma_flags_test(flags, VMA_IO_BIT)))
                        return -EINVAL;
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index 9205ebf31ce7..de429ed4d60c 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -1667,8 +1667,7 @@ static inline bool file_is_dev_zero(const struct file 
*file)
 
 static inline bool vma_flags_is_kernel_owned(const vma_flags_t *flags)
 {
-       return vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT,
-                                 VMA_IO_BIT);
+       return vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT);
 }
 
 static inline bool vma_is_kernel_owned(const struct vm_area_struct *vma)
diff --git a/tools/testing/vma/tests/merge.c b/tools/testing/vma/tests/merge.c
index acaab282939c..b26f1a66a170 100644
--- a/tools/testing/vma/tests/merge.c
+++ b/tools/testing/vma/tests/merge.c
@@ -496,17 +496,11 @@ static bool test_vma_merge_special_flags(void)
                .mm = &mm,
                .vmi = &vmi,
        };
-       vma_flag_t special_flags[] = { VMA_IO_BIT, VMA_DONTEXPAND_BIT,
+       vma_flag_t special_flags[] = { VMA_DONTEXPAND_BIT,
                VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT };
-       vma_flags_t all_special_flags = EMPTY_VMA_FLAGS;
        int i;
        struct vm_area_struct *vma_left, *vma;
 
-       /* Make sure there aren't new VM_SPECIAL flags. */
-       for (i = 0; i < ARRAY_SIZE(special_flags); i++)
-               vma_flags_set(&all_special_flags, special_flags[i]);
-       ASSERT_FLAGS_SAME_MASK(&all_special_flags, VMA_SPECIAL_FLAGS);
-
        /*
         * 01234
         * AAA
@@ -520,7 +514,7 @@ static bool test_vma_merge_special_flags(void)
         * 01234
         * AAA*
         *
-        * This should merge if not for the VM_SPECIAL flag.
+        * This should merge if not for the 'special' flag.
         */
        vmg_set_range(&vmg, 0x3000, 0x4000, 3, vma_flags);
        for (i = 0; i < ARRAY_SIZE(special_flags); i++) {

-- 
2.55.0


Reply via email to