On Mon, Aug 03, 2026 at 11:34:32AM +0200, David Hildenbrand (Arm) wrote:
> On 7/29/26 18:48, Lorenzo Stoakes (ARM) wrote:
> > This function provides the anonymous equivalent of linear_page_index(),
> > instead offsetting based on the anonymous page offset of the VMA.
> >
> > It is valid only for anonymous or MAP_PRIVATE file-backed mappings. It must
> > not be called for shared file-backed mappings.
> >
> > For pure anon VMAs, this will be equal to linear_page_index().
> >
> > Assert that both of these invariants are true In linear_anon_page_index()
> > and implement the algorithm in __linear_anon_page_index().
> >
> > Note that MAP_PRIVATE-/dev/zero mappings will satisfy vma_is_anonymous()
> > but not fulfill this invariant, so when asserting this we check
> > vma->vm_file to account for this.
> >
> > We do not update callsites yet, so no functional change intended.
> >
> > Also const-ify vma_is_anonymous() to make it compatible with the
> > const-ified linear_anon_page_index().
> >
> > VMA userland tests are also updated accordingly.
>
> In general looks good, some comments below.
>
> >
> > Signed-off-by: Lorenzo Stoakes (ARM) <[email protected]>
> > ---
> >  include/linux/mm.h              |  2 +-
> >  include/linux/pagemap.h         | 42 
> > +++++++++++++++++++++++++++++++++++++++++
> >  tools/testing/vma/include/dup.h | 25 +++++++++++++++++++++++-
> >  3 files changed, 67 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/linux/mm.h b/include/linux/mm.h
> > index df78847f5f07..64214191e7c6 100644
> > --- a/include/linux/mm.h
> > +++ b/include/linux/mm.h
> > @@ -1556,7 +1556,7 @@ static inline void vma_desc_set_anonymous(struct 
> > vm_area_desc *desc)
> >     desc->vm_ops = NULL;
> >  }
> >
> > -static inline bool vma_is_anonymous(struct vm_area_struct *vma)
> > +static inline bool vma_is_anonymous(const struct vm_area_struct *vma)
> >  {
> >     return !vma->vm_ops;
> >  }
> > diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
> > index c6fc783aaee5..259177544b03 100644
> > --- a/include/linux/pagemap.h
> > +++ b/include/linux/pagemap.h
> > @@ -1101,6 +1101,48 @@ static inline pgoff_t linear_page_index(const struct 
> > vm_area_struct *vma,
> >     return pgoff;
> >  }
> >
> > +static inline pgoff_t __linear_anon_page_index(const struct vm_area_struct 
> > *vma,
> > +                                          const unsigned long address)
>
> Nit Usual "two tab" comment (same below) :)

Ack will change.

>
> > +{
> > +   pgoff_t pgoff;
> > +
> > +   pgoff = linear_page_delta(vma, address);
> > +   pgoff += vma_start_anon_pgoff(vma);
>
>
> I'd simply do
>
>       return vma_start_anon_pgoff(vma) + linear_page_delta(vma, address);

This was just to mimic the existing thing linear_page_index() did (which in turn
was based on what the original implementation of linear_page_index()
did), will change.

>
> > +   return pgoff;
> > +}
> > +
> > +/**
> > + * linear_anon_page_index() - Determine the absolute anonymous page offset 
> > of
> > + * @address within @vma.
> > + * @vma: An anonymous or MAP_PRIVATE file-backed VMA in which @address 
> > resides.
> > + * @address: The address whose absolute page offset is required.
> > + *
> > + * This returns the anonymous page offset of @address, which is the page 
> > offset
> > + * the address possessed at the time the VMA was first faulted.
> > + *
> > + * For anonymous mappings, this returns the same value as 
> > linear_page_index().
> > + *
> > + * For MAP_PRIVATE file-backed mappings, this returns the anonymous page 
> > offset
> > + * of @address, which is the page offset the address possessed at the time 
> > the
> > + * VMA was first faulted.
> > + *
> > + * It is not valid to call this function for shared file-backed mappings.
> > + *
> > + * Returns: The absolute anonymous page offset of @address within @vma.
> > + */
> > +static inline pgoff_t linear_anon_page_index(const struct vm_area_struct 
> > *vma,
> > +                                        const unsigned long address)
>
> Dito.

Ack.

>
> > +{
> > +   const pgoff_t pgoff = __linear_anon_page_index(vma, address);
> > +
> > +   VM_WARN_ON_ONCE(vma_test(vma, VMA_SHARED_BIT));
>
> Could we test or COW mappings instead?
>
> VM_WARN_ON_ONCE(!is_cow_mapping(vma));
>
> Because we must never have anon folios is non-cow mappings.

(guessing is -> in?)

is_cow_mapping() == !VMA_SHARED_BIT && VMA_MAYWRITE_BIT

!is_cow_mapping() == VMA_SHARED_BIT || !VMA_MAYWRITE_BIT (by De Morgan's law)

So the delta here would be this being called on !VMA_MAYWRITE_BIT anon mappings.

This is called from:

* linear_folio_page_index() - tests folio is anon first so must be CoW
* __folio_set_anon() - must be CoW
* __page_check_anon_rmap() - must be CoW
* try_to_merge_with_ksm_page(), ksm_might_need_to_copy() - must be CoW

So yeah this is fine, will change!

>
> [...]
>
> > +static inline pgoff_t __linear_anon_page_index(const struct vm_area_struct 
> > *vma,
> > +                                          const unsigned long address)
> > +{
> > +   pgoff_t pgoff;
> > +
> > +   pgoff = linear_page_delta(vma, address);
> > +   pgoff += vma_start_anon_pgoff(vma);
> > +   return pgoff;
> > +}
>
> Same comment as above.

Ack, will change.

>
> --
> Cheers,
>
> David

--
Cheers, Lorenzo

Reply via email to