Re: [PATCH v3 02/15] mm: introduce linear_anon_page_index()
"Lorenzo Stoakes (ARM)" <[email protected]> Mon, 3 Aug 2026 11:10:07 +0100
| Newsgroups | org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kvack.linux-mm |
|---|---|
| Message-ID | <anBjpdMicqaGADr-@lucifer> |
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