Add CAP_HOTUNPLUG, which allows memory_hotplug to migrate a private
node's folios for the purpose of hotunplugging memory.

Without this, hotunplug fails if any folio on the node is allocated.

Add node_allows_hotunplug() - which returns true for any normal node
and private nodes with CAP_HOTUNPLUG.

Signed-off-by: Gregory Price <[email protected]>
---
 include/linux/node_private.h | 26 ++++++++++++++++++++++++++
 mm/memory_hotplug.c          |  4 ++--
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/include/linux/node_private.h b/include/linux/node_private.h
index 655fe9ec5cb61..7b617b1fa9c28 100644
--- a/include/linux/node_private.h
+++ b/include/linux/node_private.h
@@ -14,6 +14,7 @@ struct page;
  */
 #define NODE_PRIVATE_CAP_RECLAIM       (1UL << 0)      /* allow mm reclaim */
 #define NODE_PRIVATE_CAP_USER_NUMA     (1UL << 1)      /* allow mempolicy */
+#define NODE_PRIVATE_CAP_HOTUNPLUG     (1UL << 2)      /* allow hot-unplug */
 
 /**
  * struct node_private - Per-node container for N_MEMORY_PRIVATE nodes
@@ -97,6 +98,26 @@ static inline bool node_allows_user_numa(int nid)
        return ret;
 }
 
+/**
+ * node_allows_hotunplug - may hot-unplug migrate this node's folios?
+ * @nid: the node to test
+ *
+ * True for normal nodes and private nodes opted into CAP_HOTUNPLUG.
+ */
+static inline bool node_allows_hotunplug(int nid)
+{
+       struct node_private *np;
+       bool ret;
+
+       if (!node_state(nid, N_MEMORY_PRIVATE))
+               return true;
+       rcu_read_lock();
+       np = rcu_dereference(NODE_DATA(nid)->node_private);
+       ret = np && (np->caps & NODE_PRIVATE_CAP_HOTUNPLUG);
+       rcu_read_unlock();
+       return ret;
+}
+
 #else /* !CONFIG_NUMA */
 
 static inline bool folio_is_private_node(struct folio *folio)
@@ -124,6 +145,11 @@ static inline bool node_allows_user_numa(int nid)
        return true;
 }
 
+static inline bool node_allows_hotunplug(int nid)
+{
+       return true;
+}
+
 #endif /* CONFIG_NUMA */
 
 #if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 1f42ed303366c..e9573f90e0dcd 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1943,8 +1943,8 @@ static int do_migrate_range(unsigned long start_pfn, 
unsigned long end_pfn)
                        goto put_folio;
                }
 
-               /* Private node folios cannot migrate, fail outright */
-               if (folio_is_private_node(folio)) {
+               /* Fail outright on private nodes w/o hotunplug support */
+               if (!node_allows_hotunplug(folio_nid(folio))) {
                        pr_info_ratelimited("memory offline refused: node %d 
pfn %lx\n",
                                            folio_nid(folio), pfn);
                        folio_put(folio);
-- 
2.53.0-Meta


Reply via email to