linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] mm/migrate: Add migrate_device_split_page
       [not found] <20251216201206.1660899-1-francois.dugast@intel.com>
@ 2025-12-16 20:10 ` Francois Dugast
  2025-12-16 20:34   ` Matthew Wilcox
  0 siblings, 1 reply; 3+ messages in thread
From: Francois Dugast @ 2025-12-16 20:10 UTC (permalink / raw)
  To: intel-xe
  Cc: dri-devel, Matthew Brost, Andrew Morton, Balbir Singh, linux-mm,
	Francois Dugast

From: Matthew Brost <matthew.brost@intel.com>

Introduce migrate_device_split_page() to split a device page into
lower-order pages. Used when a folio allocated as higher-order is freed
and later reallocated at a smaller order by the driver memory manager.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-mm@kvack.org
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Francois Dugast <francois.dugast@intel.com>
---
 include/linux/huge_mm.h |  3 +++
 include/linux/migrate.h |  1 +
 mm/huge_memory.c        |  6 ++---
 mm/migrate_device.c     | 49 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index a4d9f964dfde..6ad8f359bc0d 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -374,6 +374,9 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list
 int folio_split_unmapped(struct folio *folio, unsigned int new_order);
 unsigned int min_order_for_split(struct folio *folio);
 int split_folio_to_list(struct folio *folio, struct list_head *list);
+int __split_unmapped_folio(struct folio *folio, int new_order,
+			   struct page *split_at, struct xa_state *xas,
+			   struct address_space *mapping, enum split_type split_type);
 int folio_check_splittable(struct folio *folio, unsigned int new_order,
 			   enum split_type split_type);
 int folio_split(struct folio *folio, unsigned int new_order, struct page *page,
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 26ca00c325d9..ec65e4fd5f88 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -192,6 +192,7 @@ void migrate_device_pages(unsigned long *src_pfns, unsigned long *dst_pfns,
 			unsigned long npages);
 void migrate_device_finalize(unsigned long *src_pfns,
 			unsigned long *dst_pfns, unsigned long npages);
+int migrate_device_split_page(struct page *page);
 
 #endif /* CONFIG_MIGRATION */
 
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 40cf59301c21..7ded35a3ecec 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3621,9 +3621,9 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
  * Return: 0 - successful, <0 - failed (if -ENOMEM is returned, @folio might be
  * split but not to @new_order, the caller needs to check)
  */
-static int __split_unmapped_folio(struct folio *folio, int new_order,
-		struct page *split_at, struct xa_state *xas,
-		struct address_space *mapping, enum split_type split_type)
+int __split_unmapped_folio(struct folio *folio, int new_order,
+			   struct page *split_at, struct xa_state *xas,
+			   struct address_space *mapping, enum split_type split_type)
 {
 	const bool is_anon = folio_test_anon(folio);
 	int old_order = folio_order(folio);
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 23379663b1e1..eb0f0e938947 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -775,6 +775,49 @@ int migrate_vma_setup(struct migrate_vma *args)
 EXPORT_SYMBOL(migrate_vma_setup);
 
 #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+/**
+ * migrate_device_split_page() - Split device page
+ * @page: Device page to split
+ *
+ * Splits a device page into smaller pages. Typically called when reallocating a
+ * folio to a smaller size. Inherently racy—only safe if the caller ensures
+ * mutual exclusion within the page's folio (i.e., no other threads are using
+ * pages within the folio). Expected to be called a free device page and
+ * restores all split out pages to a free state.
+ */
+int migrate_device_split_page(struct page *page)
+{
+	struct folio *folio = page_folio(page);
+	struct dev_pagemap *pgmap = folio->pgmap;
+	struct page *unlock_page = folio_page(folio, 0);
+	unsigned int order = folio_order(folio), i;
+	int ret = 0;
+
+	VM_BUG_ON_FOLIO(!order, folio);
+	VM_BUG_ON_FOLIO(!folio_is_device_private(folio), folio);
+	VM_BUG_ON_FOLIO(folio_ref_count(folio), folio);
+
+	folio_lock(folio);
+
+	ret = __split_unmapped_folio(folio, 0, page, NULL, NULL, SPLIT_TYPE_UNIFORM);
+	if (ret) {
+	       /*
+		* We can't fail here unless the caller doesn't know what they
+		* are doing.
+		*/
+		VM_BUG_ON_FOLIO(ret, folio);
+
+		return ret;
+	}
+
+	for (i = 0; i < 0x1 << order; ++i, ++unlock_page) {
+		page_folio(unlock_page)->pgmap = pgmap;
+		folio_unlock(page_folio(unlock_page));
+	}
+
+	return 0;
+}
+
 /**
  * migrate_vma_insert_huge_pmd_page: Insert a huge folio into @migrate->vma->vm_mm
  * at @addr. folio is already allocated as a part of the migration process with
@@ -927,6 +970,11 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,
 	return ret;
 }
 #else /* !CONFIG_ARCH_ENABLE_THP_MIGRATION */
+int migrate_device_split_page(struct page *page)
+{
+	return 0;
+}
+
 static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,
 					 unsigned long addr,
 					 struct page *page,
@@ -943,6 +991,7 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,
 	return 0;
 }
 #endif
+EXPORT_SYMBOL(migrate_device_split_page);
 
 static unsigned long migrate_vma_nr_pages(unsigned long *src)
 {
-- 
2.43.0



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/4] mm/migrate: Add migrate_device_split_page
  2025-12-16 20:10 ` [PATCH 1/4] mm/migrate: Add migrate_device_split_page Francois Dugast
@ 2025-12-16 20:34   ` Matthew Wilcox
  2025-12-16 21:39     ` Matthew Brost
  0 siblings, 1 reply; 3+ messages in thread
From: Matthew Wilcox @ 2025-12-16 20:34 UTC (permalink / raw)
  To: Francois Dugast
  Cc: intel-xe, dri-devel, Matthew Brost, Andrew Morton, Balbir Singh,
	linux-mm

On Tue, Dec 16, 2025 at 09:10:11PM +0100, Francois Dugast wrote:
> +	ret = __split_unmapped_folio(folio, 0, page, NULL, NULL, SPLIT_TYPE_UNIFORM);

We're trying to get rid of uniform splits.  Why do you need this to be
uniform?


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/4] mm/migrate: Add migrate_device_split_page
  2025-12-16 20:34   ` Matthew Wilcox
@ 2025-12-16 21:39     ` Matthew Brost
  0 siblings, 0 replies; 3+ messages in thread
From: Matthew Brost @ 2025-12-16 21:39 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Francois Dugast, intel-xe, dri-devel, Andrew Morton,
	Balbir Singh, linux-mm

On Tue, Dec 16, 2025 at 08:34:46PM +0000, Matthew Wilcox wrote:
> On Tue, Dec 16, 2025 at 09:10:11PM +0100, Francois Dugast wrote:
> > +	ret = __split_unmapped_folio(folio, 0, page, NULL, NULL, SPLIT_TYPE_UNIFORM);
> 
> We're trying to get rid of uniform splits.  Why do you need this to be
> uniform?

It’s very possible we’re doing this incorrectly due to a lack of core MM
experience. I believe Zi Yan suggested this approach (use
__split_unmapped_folio) a while back.

Let me start by explaining what we’re trying to do and see if there’s a
better suggestion for how to accomplish it.

Would SPLIT_TYPE_NON_UNIFORM split work here? Or do you have another
suggestion on how to split the folio aside from __split_unmapped_folio?

This covers the case where a GPU device page was allocated as a THP
(e.g., we call zone_device_folio_init with an order of 9). Later, this
page is freed/unmapped and then reallocated for a CPU VMA that is
smaller than a THP (e.g., we’d allocate either 4KB or 64KB based on
CPU VMA size alignment). At this point, we need to split the device
folio so we can migrate data into 4KB device pages.

Would SPLIT_TYPE_NON_UNIFORM work here? Or do you have another
suggestion for splitting the folio aside from __split_unmapped_folio?

Matt


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-12-16 21:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20251216201206.1660899-1-francois.dugast@intel.com>
2025-12-16 20:10 ` [PATCH 1/4] mm/migrate: Add migrate_device_split_page Francois Dugast
2025-12-16 20:34   ` Matthew Wilcox
2025-12-16 21:39     ` Matthew Brost

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox