Commit f784a3f1 authored by Tang Chen's avatar Tang Chen Committed by Linus Torvalds

mem-hotplug: reset node managed pages when hot-adding a new pgdat

In free_area_init_core(), zone->managed_pages is set to an approximate
value for lowmem, and will be adjusted when the bootmem allocator frees
pages into the buddy system.

But free_area_init_core() is also called by hotadd_new_pgdat() when
hot-adding memory.  As a result, zone->managed_pages of the newly added
node's pgdat is set to an approximate value in the very beginning.

Even if the memory on that node has node been onlined,
/sys/device/system/node/nodeXXX/meminfo has wrong value:

  hot-add node2 (memory not onlined)
  cat /sys/device/system/node/node2/meminfo
  Node 2 MemTotal:       33554432 kB
  Node 2 MemFree:               0 kB
  Node 2 MemUsed:        33554432 kB
  Node 2 Active:                0 kB

This patch fixes this problem by reset node managed pages to 0 after
hot-adding a new node.

1. Move reset_managed_pages_done from reset_node_managed_pages() to
   reset_all_zones_managed_pages()
2. Make reset_node_managed_pages() non-static
3. Call reset_node_managed_pages() in hotadd_new_pgdat() after pgdat
   is initialized
Signed-off-by: default avatarTang Chen <tangchen@cn.fujitsu.com>
Signed-off-by: default avatarYasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: <stable@vger.kernel.org>	[3.16+]
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 57cbc87e
...@@ -46,6 +46,7 @@ extern unsigned long init_bootmem_node(pg_data_t *pgdat, ...@@ -46,6 +46,7 @@ extern unsigned long init_bootmem_node(pg_data_t *pgdat,
extern unsigned long init_bootmem(unsigned long addr, unsigned long memend); extern unsigned long init_bootmem(unsigned long addr, unsigned long memend);
extern unsigned long free_all_bootmem(void); extern unsigned long free_all_bootmem(void);
extern void reset_node_managed_pages(pg_data_t *pgdat);
extern void reset_all_zones_managed_pages(void); extern void reset_all_zones_managed_pages(void);
extern void free_bootmem_node(pg_data_t *pgdat, extern void free_bootmem_node(pg_data_t *pgdat,
......
...@@ -243,13 +243,10 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) ...@@ -243,13 +243,10 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
static int reset_managed_pages_done __initdata; static int reset_managed_pages_done __initdata;
static inline void __init reset_node_managed_pages(pg_data_t *pgdat) void reset_node_managed_pages(pg_data_t *pgdat)
{ {
struct zone *z; struct zone *z;
if (reset_managed_pages_done)
return;
for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
z->managed_pages = 0; z->managed_pages = 0;
} }
...@@ -258,8 +255,12 @@ void __init reset_all_zones_managed_pages(void) ...@@ -258,8 +255,12 @@ void __init reset_all_zones_managed_pages(void)
{ {
struct pglist_data *pgdat; struct pglist_data *pgdat;
if (reset_managed_pages_done)
return;
for_each_online_pgdat(pgdat) for_each_online_pgdat(pgdat)
reset_node_managed_pages(pgdat); reset_node_managed_pages(pgdat);
reset_managed_pages_done = 1; reset_managed_pages_done = 1;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/stop_machine.h> #include <linux/stop_machine.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/bootmem.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -1096,6 +1097,14 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) ...@@ -1096,6 +1097,14 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
build_all_zonelists(pgdat, NULL); build_all_zonelists(pgdat, NULL);
mutex_unlock(&zonelists_mutex); mutex_unlock(&zonelists_mutex);
/*
* zone->managed_pages is set to an approximate value in
* free_area_init_core(), which will cause
* /sys/device/system/node/nodeX/meminfo has wrong data.
* So reset it to 0 before any memory is onlined.
*/
reset_node_managed_pages(pgdat);
return pgdat; return pgdat;
} }
......
...@@ -145,12 +145,10 @@ static unsigned long __init free_low_memory_core_early(void) ...@@ -145,12 +145,10 @@ static unsigned long __init free_low_memory_core_early(void)
static int reset_managed_pages_done __initdata; static int reset_managed_pages_done __initdata;
static inline void __init reset_node_managed_pages(pg_data_t *pgdat) void reset_node_managed_pages(pg_data_t *pgdat)
{ {
struct zone *z; struct zone *z;
if (reset_managed_pages_done)
return;
for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
z->managed_pages = 0; z->managed_pages = 0;
} }
...@@ -159,8 +157,12 @@ void __init reset_all_zones_managed_pages(void) ...@@ -159,8 +157,12 @@ void __init reset_all_zones_managed_pages(void)
{ {
struct pglist_data *pgdat; struct pglist_data *pgdat;
if (reset_managed_pages_done)
return;
for_each_online_pgdat(pgdat) for_each_online_pgdat(pgdat)
reset_node_managed_pages(pgdat); reset_node_managed_pages(pgdat);
reset_managed_pages_done = 1; reset_managed_pages_done = 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment