On 04.07.25 12:25, David Hildenbrand wrote:
Instead, let's use a page flag. As the page flag can result in
false-positives, glue it to the page types for which we
support/implement movable_ops page migration.

We are reusing PG_uptodate, that is for example used to track file
system state and does not apply to movable_ops pages. So
warning in case it is set in page_has_movable_ops() on other page types
could result in false-positive warnings.

Likely we could set the bit using a non-atomic update: in contrast to
page->mapping, we could have others trying to update the flags
concurrently when trying to lock the folio. In
isolate_movable_ops_page(), we already take care of that by checking if
the page has movable_ops before locking it. Let's start with the atomic
variant, we could later switch to the non-atomic variant once we are
sure other cases are similarly fine. Once we perform the switch, we'll
have to introduce __SETPAGEFLAG_NOOP().

Reviewed-by: Zi Yan <z...@nvidia.com>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoa...@oracle.com>
Signed-off-by: David Hildenbrand <da...@redhat.com>
---
  include/linux/balloon_compaction.h |  2 +-
  include/linux/migrate.h            |  8 -----
  include/linux/page-flags.h         | 54 ++++++++++++++++++++++++------
  mm/compaction.c                    |  6 ----
  mm/zpdesc.h                        |  2 +-
  5 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/include/linux/balloon_compaction.h 
b/include/linux/balloon_compaction.h
index a8a1706cc56f3..b222b0737c466 100644
--- a/include/linux/balloon_compaction.h
+++ b/include/linux/balloon_compaction.h
@@ -92,7 +92,7 @@ static inline void balloon_page_insert(struct 
balloon_dev_info *balloon,
                                       struct page *page)
  {
        __SetPageOffline(page);
-       __SetPageMovable(page);
+       SetPageMovableOps(page);
        set_page_private(page, (unsigned long)balloon);
        list_add(&page->lru, &balloon->pages);
  }
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 6aece3f3c8be8..acadd41e0b5cf 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -103,14 +103,6 @@ static inline int migrate_huge_page_move_mapping(struct 
address_space *mapping,
#endif /* CONFIG_MIGRATION */ -#ifdef CONFIG_COMPACTION
-void __SetPageMovable(struct page *page);
-#else
-static inline void __SetPageMovable(struct page *page)
-{
-}
-#endif
-
  #ifdef CONFIG_NUMA_BALANCING
  int migrate_misplaced_folio_prepare(struct folio *folio,
                struct vm_area_struct *vma, int node);
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 4c27ebb689e3c..5f2b570735852 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -170,6 +170,11 @@ enum pageflags {
        /* non-lru isolated movable page */
        PG_isolated = PG_reclaim,
+#ifdef CONFIG_MIGRATION
+       /* this is a movable_ops page (for selected typed pages only) */
+       PG_movable_ops = PG_uptodate,
+#endif
+
        /* Only valid for buddy pages. Used to track pages that are reported */
        PG_reported = PG_uptodate,
@@ -698,9 +703,6 @@ PAGEFLAG_FALSE(VmemmapSelfHosted, vmemmap_self_hosted)
   * bit; and then folio->mapping points, not to an anon_vma, but to a private
   * structure which KSM associates with that merged page.  See ksm.h.
   *
- * PAGE_MAPPING_KSM without PAGE_MAPPING_ANON is used for non-lru movable
- * page and then folio->mapping points to a struct movable_operations.
- *
   * Please note that, confusingly, "folio_mapping" refers to the inode
   * address_space which maps the folio from disk; whereas "folio_mapped"
   * refers to user virtual address space into which the folio is mapped.
@@ -743,13 +745,6 @@ static __always_inline bool PageAnon(const struct page 
*page)
  {
        return folio_test_anon(page_folio(page));
  }
-
-static __always_inline bool page_has_movable_ops(const struct page *page)
-{
-       return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) ==
-                               PAGE_MAPPING_MOVABLE;
-}
-
  #ifdef CONFIG_KSM
  /*
   * A KSM page is one of those write-protected "shared pages" or "merged pages"
@@ -1133,6 +1128,45 @@ bool is_free_buddy_page(const struct page *page);
PAGEFLAG(Isolated, isolated, PF_ANY); +#ifdef CONFIG_MIGRATION
+/*
+ * This page is migratable through movable_ops (for selected typed pages
+ * only).
+ *
+ * Page migration of such pages might fail, for example, if the page is
+ * already isolated by somebody else, or if the page is about to get freed.
+ *
+ * While a subsystem might set selected typed pages that support page migration
+ * as being movable through movable_ops, it must never clear this flag.
+ *
+ * This flag is only cleared when the page is freed back to the buddy.
+ *
+ * Only selected page types support this flag (see page_movable_ops()) and
+ * the flag might be used in other context for other pages. Always use
+ * page_has_movable_ops() instead.
+ */
+TESTPAGEFLAG(MovableOps, movable_ops, PF_NO_TAIL);
+SETPAGEFLAG(MovableOps, movable_ops, PF_NO_TAIL);
+#else /* !CONFIG_MIGRATION */
+TESTPAGEFLAG_FALSE(MovableOps, movable_ops);
+SETPAGEFLAG_NOOP(MovableOps, movable_ops);
+#endif /* CONFIG_MIGRATION */
+
+/**
+ * page_has_movable_ops - test for a movable_ops page
+ * @page The page to test.
+ *
+ * Test whether this is a movable_ops page. Such pages will stay that
+ * way until freed.
+ *
+ * Returns true if this is a movable_ops page, otherwise false.
+ */
+static inline bool page_has_movable_ops(const struct page *page)
+{
+       return PageMovableOps(page) &&
+              (PageOffline(page) || PageZsmalloc(page));
+}
+

The following fixup on top:

From 3a52911a299d3328d9fa2aeba00170240795702d Mon Sep 17 00:00:00 2001
From: David Hildenbrand <da...@redhat.com>
Date: Fri, 11 Jul 2025 11:57:43 +0200
Subject: [PATCH] fixup: "mm: convert "movable" flag in page->mapping to a page
 flag"

We're missing a ":".

Signed-off-by: David Hildenbrand <da...@redhat.com>
---
 include/linux/page-flags.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 970600d79daca..8e4d6eda8a8d6 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -1150,7 +1150,7 @@ PAGEFLAG_FALSE(MovableOpsIsolated, movable_ops_isolated);
/**
  * page_has_movable_ops - test for a movable_ops page
- * @page The page to test.
+ * @page: The page to test.
  *
  * Test whether this is a movable_ops page. Such pages will stay that
  * way until freed.
--
2.50.1


--
Cheers,

David / dhildenb


Reply via email to