Re: [PATCH RFC v4 04/12] mm/gup: let check_vma_flags() ignore selected VMA flags
From: Suren Baghdasaryan
Date: Mon Jul 27 2026 - 11:20:25 EST
On Fri, Jul 24, 2026 at 3:30 PM Rik van Riel <riel@xxxxxxxxxxx> wrote:
>
> check_vma_flags() rejects a VMA whose flags gup cannot handle. A caller
> that wants to reach a COWed page in a VM_IO or VM_PFNMAP VMA, where that
> page does have a struct page, cannot express the exception and has to
> repeat the flag test itself.
>
> Add an ignore_flags argument that check_vma_flags() clears from its local
> copy of vma->vm_flags before the flag checks. A caller can drop a single
> rejection this way while keeping every other check. All current callers
> pass 0.
>
> This prepares for get_user_page_vma(), which passes VM_IO | VM_PFNMAP to
> reach those COWed pages.
>
> No functional change intended.
>
> Assisted-by: Claude:claude-opus-4.8
> Signed-off-by: Rik van Riel <riel@xxxxxxxxxxx>
Reviewed-by: Suren Baghdasaryan <surenb@xxxxxxxxxx>
> ---
> mm/gup.c | 14 +++++++++++---
> 1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/mm/gup.c b/mm/gup.c
> index 0692119b7904..dcece7b5253c 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -1197,13 +1197,21 @@ static bool writable_file_mapping_allowed(struct vm_area_struct *vma,
> return !vma_needs_dirty_tracking(vma);
> }
>
> -static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
> +static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags,
> + vm_flags_t ignore_flags)
> {
> vm_flags_t vm_flags = vma->vm_flags;
> int write = (gup_flags & FOLL_WRITE);
> int foreign = (gup_flags & FOLL_REMOTE);
> bool vma_anon = vma_is_anonymous(vma);
>
> + /*
> + * Opt out of the flag checks that read this local copy (the
> + * VM_IO/VM_PFNMAP gate and the write/read/cow bits); checks that
> + * re-read vma->vm_flags through helpers are unaffected.
> + */
> + vm_flags &= ~ignore_flags;
> +
> if (vm_flags & (VM_IO | VM_PFNMAP))
> return -EFAULT;
>
> @@ -1387,7 +1395,7 @@ static long __get_user_pages(struct mm_struct *mm,
> ret = -ENOMEM;
> goto out;
> }
> - if (check_vma_flags(vma, gup_flags)) {
> + if (check_vma_flags(vma, gup_flags, 0)) {
> ret = -EINVAL;
> goto out;
> }
> @@ -1408,7 +1416,7 @@ static long __get_user_pages(struct mm_struct *mm,
> ret = -EFAULT;
> goto out;
> }
> - ret = check_vma_flags(vma, gup_flags);
> + ret = check_vma_flags(vma, gup_flags, 0);
> if (ret)
> goto out;
> }
> --
> 2.53.0-Meta
>
>