From: "David Hildenbrand (Arm)" <david@kernel.org>
To: Rik van Riel <riel@surriel.com>, linux-kernel@vger.kernel.org
Cc: Andrew Morton <akpm@linux-foundation.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
John Hubbard <jhubbard@nvidia.com>, Peter Xu <peterx@redhat.com>,
Suren Baghdasaryan <surenb@google.com>,
Yuan-Hao Hsu <aa9736195201@gmail.com>,
Christoph Hellwig <hch@infradead.org>,
linux-mm@kvack.org
Subject: Re: [PATCH 1/8] mm/gup: break out gup_fill_pages() helper
Date: Tue, 3 Nov 2026 17:39:10 +0100 [thread overview]
Message-ID: <856ed0da-d806-4f2e-95e7-f276f2408e8d@kernel.org> (raw)
In-Reply-To: <3a7d12b52a5de61277842f2cca0dd90d42728135.camel@surriel.com>
On 11/3/26 17:29, Rik van Riel wrote:
> On Tue, 2026-11-03 at 09:43 +0100, David Hildenbrand (Arm) wrote:
>> On 11/2/26 20:30, Rik van Riel wrote:
>>> __get_user_pages() fills pages[] and flushes each page's caches in
>>> an
>>> open-coded loop.
>>>
>>> Move it into a gup_fill_pages() helper, which the
>>> follow_page_mask()
>>> call chain can then use to fill its own pages[] slots.
>>>
>>> No functional changes intended.
>>>
>>> Suggested-by: David Hildenbrand <david@kernel.org>
>>> Reviewed-by: Suren Baghdasaryan <surenb@google.com>
>>> Signed-off-by: Rik van Riel <riel@surriel.com>
>>> ---
>>> mm/gup.c | 27 ++++++++++++++++++---------
>>> 1 file changed, 18 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/mm/gup.c b/mm/gup.c
>>> index 7d43ce717b246..cdbe2ed3e6442 100644
>>> --- a/mm/gup.c
>>> +++ b/mm/gup.c
>>> @@ -633,6 +633,23 @@ static struct page *no_page_table(struct
>>> vm_area_struct *vma,
>>> return NULL;
>>> }
>>>
>>> +static void gup_fill_pages(struct vm_area_struct *vma, unsigned
>>> long address,
>>> + struct page *page, unsigned long nr, struct page
>>> **pages)
>>
>> unsigned long nr_pages ?
>
> Will do. Thank you.
>>
>>
>>> +{
>>> + unsigned long i;
>>> +
>>> + if (!pages)
>>> + return;
>>
>> Why is that check needed? Why should someone try filling something
>> that doesn't
>> exist?
>
> faultin_page_range() and populate_vma_page_range
> both call the GUP code with a NULL pages pointer.
That's not what I meant. I know that we have GUP users without
pages array.
In the code change you are performing the check is not required.
That's why there wasn't one in the first place.
>
>>
>>> +
>>> + for (i = 0; i < nr; i++) {
>>> + struct page *subpage = page + i;
>>
>> There is no such thing as a subpage as Willy keeps saying :)
>>
>> Why not reuse "page" ?
>>
>> for (i = 0; i < nr; i++, page++) {
>
> Will do.
>
>>
>>> +
>>> + pages[i] = subpage;
>>> + flush_anon_page(vma, subpage, address + i *
>>> PAGE_SIZE);
>>> + flush_dcache_page(subpage);
>>
>> Now I wonder why GUP-fast doesn't need any of that. Likely because
>> architectures
>> that support GUP-fast don't need any such magic.
>
> These cache flushes seem to be common on architectures
> with virtually indexed caches, where the cache needs
> to be flushed if the memory is accessed through a
> different virtual address than where userspace might
> have written data.
>
> On 32 bit ARM, MIPS, and sh, the kernel seems to
> implement an actual cache flush here, but also
> claims to support GUP-fast.
>
> I don't understand how that would possibly be safe,
> since the pages returned by GUP-fast could be
> accessed under a different cache alias than where
> userspace accesses the memory.
Right. What a mess. Once again :)
>
> I think one reason GUP-fast can get away without
> a dcache flush is that most of the callers take
> care of that, for example by using raw_copy_to_user()
> to copy data using the user's virtual address, which
> takes care of VIVT cache aliasing.
>
> Likewise, drivers that do zero-copy DMA into user
> memory will get the cache flushed on VIVT architectures
> inside dma_unmap().
>
> The dcache flush inside GUP covers rarer cases, where
> the kernel accesses memory at a different address than
> where userspace wrote to that memory.
>
> cat /proc/<pid>/cmdline KERNEL
> ---- -------------------
> read(buf=U)
> -------------------------------->
> get_mm_cmdline(mm, U):
> access_remote_vm(mm, arg_start,
> kbuf, len, FOLL_ANON):
> get_user_page_vma_remote()
> (slow GUP + its flushes)
> kmap_local_folio(P)
> memcpy(kbuf <- K) // read
> kunmap_local(K)
> copy_to_user(U, kbuf) // write
> through U itself
> read buf at U
> ------>
> clean: the final write to U went
> through U. Same line. No hazard.
>
> In this case, the dcache flush in slow GUP ensures
> that data written before the GUP is visible to the
> reader.
>
> In the write path, e.g. for PTRACE_POKE, __access_remote_vm
> flushes after the write has been done, so the other
> process will see the data on the next read.
>
> It looks like process_vm_writev() might be missing that
> cache flush after a write, though.
:(
>
> However, now we have a situation where:
> 1) Only a few oddball callers of GUP need the dcache flush, and
> 2) Those need to do their OWN flush after a write, and
> 3) The dcache flush is not needed for most other GUP callers.
>
> We could do two different things here to solve the
> asymmetry.
>
> Either we could add dcache flushing to
> unpin_user_pages_dirty_lock(), and make sure all
> the callers that need to call that function, or
> we could move the cache flushing to the GUP callers.
>
> Then we have KSM, which uses GUP, and which would like
> to see the latest page contents...
It's all very inconsistent. And undocumented. And error prone.
Could we have GUP-fast also flush the dcache for consistency or
must that only be called with the PT lock held?
>
>>
>> Maybe we should in fact base this on the gup-fast batching series and
>> also use
>> the helper in there (passing vma=NULL)?
>
> I just moved this code out of __get_user_pages(),
> but if we can get rid of it completely by using
> a different helper, all the better.
>
> Which GUP-fast batching series are you talking
> about, here?
>
> In Yeoreum Yun's series, the batch filling seems
> to be done inline in gup_fast_pte_range(), and not
> in a helper:
>
> https://lore.kernel.org/all/20261102-refactor_gup_fast-v2-4-bc1ac018c834@arm.com/
>
> Should both paths be using the same gup_fill_pages()
> helper?
We also have gup_fast_pmd_leaf that fills an array. I think all of these should
just use a helper (instead of manually looping).
For now we can distinguish gup vs. gup-fast using the VMA argument.
--
Cheers,
David
next prev parent reply other threads:[~2026-11-03 16:39 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 19:30 [RFC PATCH v5 0/8] batch lookups in follow_page_mask() Rik van Riel
2026-11-02 19:30 ` [PATCH 1/8] mm/gup: break out gup_fill_pages() helper Rik van Riel
2026-11-03 8:43 ` David Hildenbrand (Arm)
2026-11-03 16:29 ` Rik van Riel
2026-11-03 16:39 ` David Hildenbrand (Arm) [this message]
2026-11-03 17:00 ` Rik van Riel
2026-11-03 17:04 ` David Hildenbrand (Arm)
2026-11-03 19:30 ` Rik van Riel
2026-11-02 19:30 ` [PATCH 2/8] mm/gup: convert follow_page_mask() to return a long Rik van Riel
2026-11-02 19:30 ` [PATCH 3/8] mm/gup: split out folio grab-and-store helper Rik van Riel
2026-11-02 19:30 ` [PATCH 4/8] mm/gup: break out gup_lookup_pte() helper Rik van Riel
2026-11-02 19:30 ` [PATCH 5/8] mm/gup: fill the pages array outside the pud/pmd lock Rik van Riel
2026-11-02 19:30 ` [PATCH 6/8] mm/gup: return a huge page's full count from follow_page_mask() Rik van Riel
2026-11-02 19:30 ` [PATCH 7/8] mm/gup: walk multiple PTEs per follow_page_pte() call Rik van Riel
2026-11-02 19:30 ` [PATCH 8/8] mm/gup: batch contiguous same-folio PTEs into one refcount grab Rik van Riel
2026-11-03 8:35 ` David Hildenbrand (Arm)
2026-11-03 16:42 ` Rik van Riel
2026-11-03 16:55 ` David Hildenbrand (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=856ed0da-d806-4f2e-95e7-f276f2408e8d@kernel.org \
--to=david@kernel.org \
--cc=aa9736195201@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=hch@infradead.org \
--cc=jgg@ziepe.ca \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=peterx@redhat.com \
--cc=riel@surriel.com \
--cc=surenb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®