On Wed, 27 Aug 2025 12:10:55 -0600, alex.williamson@xxxxxxxxxx wrote: > On Thu, 14 Aug 2025 14:47:10 +0800 > lizhe.67@xxxxxxxxxxxxx wrote: > > > From: Li Zhe <lizhe.67@xxxxxxxxxxxxx> > > > > Let's add a simple helper for determining the number of contiguous pages > > that represent contiguous PFNs. > > > > In an ideal world, this helper would be simpler or not even required. > > Unfortunately, on some configs we still have to maintain (SPARSEMEM > > without VMEMMAP), the memmap is allocated per memory section, and we might > > run into weird corner cases of false positives when blindly testing for > > contiguous pages only. > > > > One example of such false positives would be a memory section-sized hole > > that does not have a memmap. The surrounding memory sections might get > > "struct pages" that are contiguous, but the PFNs are actually not. > > > > This helper will, for example, be useful for determining contiguous PFNs > > in a GUP result, to batch further operations across returned "struct > > page"s. VFIO will utilize this interface to accelerate the VFIO DMA map > > process. > > > > Implementation based on Linus' suggestions to avoid new usage of > > nth_page() where avoidable. > > > > Suggested-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> > > Suggested-by: Jason Gunthorpe <jgg@xxxxxxxx> > > Signed-off-by: Li Zhe <lizhe.67@xxxxxxxxxxxxx> > > Co-developed-by: David Hildenbrand <david@xxxxxxxxxx> > > Signed-off-by: David Hildenbrand <david@xxxxxxxxxx> > > --- > > include/linux/mm.h | 7 ++++++- > > include/linux/mm_inline.h | 35 +++++++++++++++++++++++++++++++++++ > > 2 files changed, 41 insertions(+), 1 deletion(-) > > > Does this need any re-evaluation after Willy's series?[1] Patch 2/ > changes page_to_section() to memdesc_section() which takes a new > memdesc_flags_t, ie. page->flags. The conversion appears trivial, but > mm has many subtleties. > > Ideally we could also avoid merge-time fixups for linux-next and > mainline. Thank you for your reminder. In my view, if Willy's series is integrated, this patch will need to be revised as follows. Please correct me if I'm wrong. diff --git a/include/linux/mm.h b/include/linux/mm.h index ab4d979f4eec..bad0373099ad 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1763,7 +1763,12 @@ static inline unsigned long memdesc_section(memdesc_flags_t mdf) { return (mdf.f >> SECTIONS_PGSHIFT) & SECTIONS_MASK; } -#endif +#else /* !SECTION_IN_PAGE_FLAGS */ +static inline unsigned long memdesc_section(memdesc_flags_t mdf) +{ + return 0; +} +#endif /* SECTION_IN_PAGE_FLAGS */ /** * folio_pfn - Return the Page Frame Number of a folio. diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 150302b4a905..bb23496d465b 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -616,4 +616,40 @@ static inline bool vma_has_recency(struct vm_area_struct *vma) return true; } +/** + * num_pages_contiguous() - determine the number of contiguous pages + * that represent contiguous PFNs + * @pages: an array of page pointers + * @nr_pages: length of the array, at least 1 + * + * Determine the number of contiguous pages that represent contiguous PFNs + * in @pages, starting from the first page. + * + * In some kernel configs contiguous PFNs will not have contiguous struct + * pages. In these configurations num_pages_contiguous() will return a num + * smaller than ideal number. The caller should continue to check for pfn + * contiguity after each call to num_pages_contiguous(). + * + * Returns the number of contiguous pages. + */ +static inline size_t num_pages_contiguous(struct page **pages, size_t nr_pages) +{ + struct page *cur_page = pages[0]; + unsigned long section = memdesc_section(cur_page->flags); + size_t i; + + for (i = 1; i < nr_pages; i++) { + if (++cur_page != pages[i]) + break; + /* + * In unproblematic kernel configs, page_to_section() == 0 and + * the whole check will get optimized out. + */ + if (memdesc_section(cur_page->flags) != section) + break; + } + + return i; +} + #endif --- Thanks, Zhe