mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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

  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®