+ mm-memory_hotplug-fix-try_offline_node.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled
     Subject: mm/memory_hotplug: fix try_offline_node()
has been added to the -mm tree.  Its filename is
     mm-memory_hotplug-fix-try_offline_node.patch

This patch should soon appear at
    http://ozlabs.org/~akpm/mmots/broken-out/mm-memory_hotplug-fix-try_offline_node.patch
and later at
    http://ozlabs.org/~akpm/mmotm/broken-out/mm-memory_hotplug-fix-try_offline_node.patch

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***

The -mm tree is included into linux-next and is updated
there every 3-4 working days

------------------------------------------------------
From: David Hildenbrand <david@xxxxxxxxxx>
Subject: mm/memory_hotplug: fix try_offline_node()

try_offline_node() is pretty much broken right now:

- The node span is updated when onlining memory, not when adding it.  We
  ignore memory that was mever onlined.  Bad.

- We touch possible garbage memmaps.  The pfn_to_nid(pfn) can easily
  trigger a kernel panic.  Bad for memory that is offline but also bad for
  subsection hotadd with ZONE_DEVICE, whereby the memmap of the first PFN
  of a section might contain garbage.

- Sections belonging to mixed nodes are not properly considered.

As memory blocks might belong to multiple nodes, we would have to walk all
pageblocks (or at least subsections) within present sections.  However, we
don't have a way to identify whether a memmap that is not online was
initialized (relevant for ZONE_DEVICE).  This makes things more
complicated.

Luckily, we can piggy pack on the node span and the sysfs links between
memory blocks and the node.  Currently, the node span is grown when
calling move_pfn_range_to_zone() - e.g., when onlining memory, and shrunk
when removing memory, before calling try_offline_node().  Sysfs links are
created via link_mem_sections(), e.g., during boot or when adding memory.

If the node still spans memory or if any memory block is linked to the
node in sysfs, we don't set the node offline.  Without CONFIG_NUMA, or
without CONFIG_SYSFS, we will simply always detect the node as being
linked to the memory block and not set the node offline.

Add a way to test if a sysfs link exists.

Note: We will soon stop shrinking the ZONE_DEVICE zone and the node span
when removing ZONE_DEVICE memory to fix similar issues (acess of garbage
memmaps) - until we have a reliable way to identify whether these memmaps
were properly initialized.  This implies later, that once a node had
ZONE_DEVICE memory, we won't be able to set a node offline - which should
be acceptable.

Since commit f1dd2cd13c4b ("mm, memory_hotplug: do not associate hotadded
memory to zones until online") memory that is added is not assoziated with
a zone/node (memmap not initialized).  The introducing commit 60a5a19e7419
("memory-hotplug: remove sysfs file of node") already missed that we could
have multiple nodes for a section and that the zone/node span is updated
when onlining pages, not when adding them.

I tested this by hotplugging two DIMMs to a memory-less and cpu-less NUMA
node.  The node is properly onlined when adding the DIMMs.  When removing
the DIMMs, the node is properly offlined.

Link: http://lkml.kernel.org/r/20191028105458.28320-1-david@xxxxxxxxxx
Fixes: 60a5a19e7419 ("memory-hotplug: remove sysfs file of node")
Fixes: f1dd2cd13c4b ("mm, memory_hotplug: do not associate hotadded memory to zones until online") # visiable after d0dc12e86b319
Signed-off-by: David Hildenbrand <david@xxxxxxxxxx>
Cc: Tang Chen <tangchen@xxxxxxxxxxxxxx>
Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
Cc: "Rafael J. Wysocki" <rafael@xxxxxxxxxx>
Cc: Keith Busch <keith.busch@xxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: "Peter Zijlstra (Intel)" <peterz@xxxxxxxxxxxxx>
Cc: Jani Nikula <jani.nikula@xxxxxxxxx>
Cc: Nayna Jain <nayna@xxxxxxxxxxxxx>
Cc: Michal Hocko <mhocko@xxxxxxxx>
Cc: Oscar Salvador <osalvador@xxxxxxx>
Cc: Stephen Rothwell <sfr@xxxxxxxxxxxxxxxx>
Cc: Dan Williams <dan.j.williams@xxxxxxxxx>
Cc: Pavel Tatashin <pasha.tatashin@xxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
---

 drivers/base/node.c   |    9 +++++++
 fs/sysfs/symlink.c    |   21 ++++++++++++++++++
 include/linux/node.h  |    7 ++++++
 include/linux/sysfs.h |    6 +++++
 mm/memory_hotplug.c   |   46 ++++++++++++++++++++++++----------------
 5 files changed, 71 insertions(+), 18 deletions(-)

--- a/drivers/base/node.c~mm-memory_hotplug-fix-try_offline_node
+++ a/drivers/base/node.c
@@ -836,6 +836,15 @@ int link_mem_sections(int nid, unsigned
 				  register_mem_sect_under_node);
 }
 
+bool memory_block_registered_under_node(struct memory_block *mem, int nid)
+{
+	if (mem->nid == nid)
+		return true;
+	/* memory blocks can span multiple nodes. Check against the link. */
+	return sysfs_link_exists(&mem->dev.kobj,
+				 kobject_name(&node_devices[nid]->dev.kobj));
+}
+
 #ifdef CONFIG_HUGETLBFS
 /*
  * Handle per node hstate attribute [un]registration on transistions
--- a/fs/sysfs/symlink.c~mm-memory_hotplug-fix-try_offline_node
+++ a/fs/sysfs/symlink.c
@@ -154,6 +154,27 @@ void sysfs_remove_link(struct kobject *k
 EXPORT_SYMBOL_GPL(sysfs_remove_link);
 
 /**
+ *	sysfs_link_exists - test if a symlink exists in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@name:	name of the symlink to test.
+ */
+bool sysfs_link_exists(struct kobject *kobj, const char *name)
+{
+	struct kernfs_node *parent = NULL, *kn;
+
+	if (!kobj)
+		parent = sysfs_root_kn;
+	else
+		parent = kobj->sd;
+
+	kn = kernfs_find_and_get(parent, name);
+	kernfs_put(kn);
+
+	return kn != NULL;
+}
+EXPORT_SYMBOL_GPL(sysfs_link_exists);
+
+/**
  *	sysfs_rename_link_ns - rename symlink in object's directory.
  *	@kobj:	object we're acting for.
  *	@targ:	object we're pointing to.
--- a/include/linux/node.h~mm-memory_hotplug-fix-try_offline_node
+++ a/include/linux/node.h
@@ -138,6 +138,8 @@ extern void unregister_one_node(int nid)
 extern int register_cpu_under_node(unsigned int cpu, unsigned int nid);
 extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid);
 extern void unregister_memory_block_under_nodes(struct memory_block *mem_blk);
+extern bool memory_block_registered_under_node(struct memory_block *mem,
+					       int nid);
 
 extern int register_memory_node_under_compute_node(unsigned int mem_nid,
 						   unsigned int cpu_nid,
@@ -171,6 +173,11 @@ static inline int unregister_cpu_under_n
 static inline void unregister_memory_block_under_nodes(struct memory_block *mem_blk)
 {
 }
+static inline bool memory_block_registered_under_node(struct memory_block *mem,
+						      int nid)
+{
+	return true;
+}
 
 static inline void register_hugetlbfs_with_node(node_registration_func_t reg,
 						node_registration_func_t unreg)
--- a/include/linux/sysfs.h~mm-memory_hotplug-fix-try_offline_node
+++ a/include/linux/sysfs.h
@@ -265,6 +265,7 @@ int __must_check sysfs_create_link_nowar
 					  struct kobject *target,
 					  const char *name);
 void sysfs_remove_link(struct kobject *kobj, const char *name);
+bool sysfs_link_exists(struct kobject *kobj, const char *name);
 
 int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target,
 			 const char *old_name, const char *new_name,
@@ -420,6 +421,11 @@ static inline void sysfs_remove_link(str
 {
 }
 
+static inline bool sysfs_link_exists(struct kobject *kobj, const char *name)
+{
+	return true;
+}
+
 static inline int sysfs_rename_link_ns(struct kobject *k, struct kobject *t,
 				       const char *old_name,
 				       const char *new_name, const void *ns)
--- a/mm/memory_hotplug.c~mm-memory_hotplug-fix-try_offline_node
+++ a/mm/memory_hotplug.c
@@ -1631,6 +1631,15 @@ static int check_cpu_on_node(pg_data_t *
 	return 0;
 }
 
+static int check_no_memblock_registered_under_node_cb(struct memory_block *mem,
+						      void *arg)
+{
+
+	const int nid = *(int *)arg;
+
+	return memory_block_registered_under_node(mem, nid) ? -EEXIST : 0;
+}
+
 /**
  * try_offline_node
  * @nid: the node ID
@@ -1642,26 +1651,27 @@ static int check_cpu_on_node(pg_data_t *
  */
 void try_offline_node(int nid)
 {
+	unsigned long end_pfn = section_nr_to_pfn(__highest_present_section_nr);
 	pg_data_t *pgdat = NODE_DATA(nid);
-	unsigned long start_pfn = pgdat->node_start_pfn;
-	unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages;
-	unsigned long pfn;
-
-	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
-		unsigned long section_nr = pfn_to_section_nr(pfn);
-
-		if (!present_section_nr(section_nr))
-			continue;
-
-		if (pfn_to_nid(pfn) != nid)
-			continue;
-
-		/*
-		 * some memory sections of this node are not removed, and we
-		 * can't offline node now.
-		 */
+	int rc;
+
+	/*
+	 * If the node still spans pages (especially ZONE_DEVICE), don't
+	 * offline it. A node spans memory after move_pfn_range_to_zone(),
+	 * e.g., after the memory block was onlined.
+	 */
+	if (pgdat->node_spanned_pages)
+		return;
+
+	/*
+	 * Especially offline memory blocks might not be spanned by the
+	 * node. They will get spanned by the node once they get onlined.
+	 * However, they link to the node in sysfs and can get onlined later.
+	 */
+	rc = walk_memory_blocks(0, PFN_PHYS(end_pfn), &nid,
+				check_no_memblock_registered_under_node_cb);
+	if (rc)
 		return;
-	}
 
 	if (check_cpu_on_node(pgdat))
 		return;
_

Patches currently in -mm which might be from david@xxxxxxxxxx are

mm-memory_hotplug-export-generic_online_page.patch
hv_balloon-use-generic_online_page.patch
mm-memory_hotplug-remove-__online_page_free-and-__online_page_increment_counters.patch
mm-memory_hotplug-dont-access-uninitialized-memmaps-in-shrink_zone_span.patch
mm-memory_hotplug-shrink-zones-when-offlining-memory.patch
mm-memory_hotplug-poison-memmap-in-remove_pfn_range_from_zone.patch
mm-memory_hotplug-we-always-have-a-zone-in-find_smallestbiggest_section_pfn.patch
mm-memory_hotplug-dont-check-for-all-holes-in-shrink_zone_span.patch
mm-memory_hotplug-drop-local-variables-in-shrink_zone_span.patch
mm-memory_hotplug-cleanup-__remove_pages.patch
mm-page_allocc-dont-set-pages-pagereserved-when-offlining.patch
mm-page_isolationc-convert-skip_hwpoison-to-memory_offline.patch
mm-memory_hotplug-fix-try_offline_node.patch




[Index of Archives]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux