On 3/6/25 19:16, Mika Penttilä wrote: > Hi, > > On 3/6/25 06:42, Balbir Singh wrote: >> When a zone device page is split (via huge pmd folio split). The >> driver callback for folio_split is invoked to let the device driver >> know that the folio size has been split into a smaller order. >> >> The HMM test driver has been updated to handle the split, since the >> test driver uses backing pages, it requires a mechanism of reorganizing >> the backing pages (backing pages are used to create a mirror device) >> again into the right sized order pages. This is supported by exporting >> prep_compound_page(). >> >> Signed-off-by: Balbir Singh <balbirs@xxxxxxxxxx> >> --- >> include/linux/memremap.h | 7 +++++++ >> include/linux/mm.h | 1 + >> lib/test_hmm.c | 35 +++++++++++++++++++++++++++++++++++ >> mm/huge_memory.c | 5 +++++ >> mm/page_alloc.c | 1 + >> 5 files changed, 49 insertions(+) >> >> diff --git a/include/linux/memremap.h b/include/linux/memremap.h >> index 11d586dd8ef1..2091b754f1da 100644 >> --- a/include/linux/memremap.h >> +++ b/include/linux/memremap.h >> @@ -100,6 +100,13 @@ struct dev_pagemap_ops { >> */ >> int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn, >> unsigned long nr_pages, int mf_flags); >> + >> + /* >> + * Used for private (un-addressable) device memory only. >> + * This callback is used when a folio is split into >> + * a smaller folio >> + */ >> + void (*folio_split)(struct folio *head, struct folio *tail); >> }; >> >> #define PGMAP_ALTMAP_VALID (1 << 0) >> diff --git a/include/linux/mm.h b/include/linux/mm.h >> index 98a67488b5fe..3d0e91e0a923 100644 >> --- a/include/linux/mm.h >> +++ b/include/linux/mm.h >> @@ -1415,6 +1415,7 @@ static inline struct folio *virt_to_folio(const void *x) >> void __folio_put(struct folio *folio); >> >> void split_page(struct page *page, unsigned int order); >> +void prep_compound_page(struct page *page, unsigned int order); >> void folio_copy(struct folio *dst, struct folio *src); >> int folio_mc_copy(struct folio *dst, struct folio *src); >> >> diff --git a/lib/test_hmm.c b/lib/test_hmm.c >> index a81d2f8a0426..18b6a7b061d7 100644 >> --- a/lib/test_hmm.c >> +++ b/lib/test_hmm.c >> @@ -1640,10 +1640,45 @@ static vm_fault_t dmirror_devmem_fault(struct vm_fault *vmf) >> return ret; >> } >> >> + >> +static void dmirror_devmem_folio_split(struct folio *head, struct folio *tail) >> +{ >> + struct page *rpage = BACKING_PAGE(folio_page(head, 0)); >> + struct folio *new_rfolio; >> + struct folio *rfolio; >> + unsigned long offset = 0; >> + >> + if (!rpage) { >> + folio_page(tail, 0)->zone_device_data = NULL; >> + return; >> + } >> + >> + offset = folio_pfn(tail) - folio_pfn(head); >> + rfolio = page_folio(rpage); >> + new_rfolio = page_folio(folio_page(rfolio, offset)); >> + >> + folio_page(tail, 0)->zone_device_data = folio_page(new_rfolio, 0); >> + > >> + if (folio_pfn(tail) - folio_pfn(head) == 1) { >> + if (folio_order(head)) >> + prep_compound_page(folio_page(rfolio, 0), >> + folio_order(head)); >> + folio_set_count(rfolio, 1); >> + } > > I think this might need at least a comment. Also, isn't the > folio_order(head) always 0, tail and head are splitted folios and if pfn > difference == 1? > If the intention is to adjust the backing folio's head page to the new > order, shouldn't there be clear_compound_head() also for backing head > page if split to zero order? > I'll add some comments to clarify, I'll add clear_compound_head() Thanks, Balbir