Skip to content

Commit

Permalink
memory-hotplug: fix wrong edge when hot add a new node
Browse files Browse the repository at this point in the history
When we add a new node, the edge of memory may be wrong.

e.g. system has 4 nodes, and node3 is movable, node3 mem:[24G-32G],

1. hotremove the node3,
2. then hotadd node3 with a part of memory, mem:[26G-30G],
3. call hotadd_new_pgdat()
        free_area_init_node()
                get_pfn_range_for_nid()
4. it will return wrong start_pfn and end_pfn, because we have not
update the memblock.

This patch also fixes a BUG_ON during hot-addition, please see
http://marc.info/?l=linux-kernel&m=142961156129456&w=2

Signed-off-by: Xishi Qiu <[email protected]>
Cc: Yasuaki Ishimatsu <[email protected]>
Cc: Kamezawa Hiroyuki <[email protected]>
Cc: Taku Izumi <[email protected]>
Cc: Tang Chen <[email protected]>
Cc: Gu Zheng <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Xishi Qiu authored and torvalds committed Aug 14, 2015
1 parent 2baf9e8 commit f9126ab
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 0 deletions.
3 changes: 3 additions & 0 deletions mm/memory_hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,7 @@ int __ref add_memory(int nid, u64 start, u64 size)

/* create new memmap entry */
firmware_map_add_hotplug(start, start + size, "System RAM");
memblock_add_node(start, size, nid);

goto out;

Expand Down Expand Up @@ -2013,6 +2014,8 @@ void __ref remove_memory(int nid, u64 start, u64 size)

/* remove memmap entry */
firmware_map_remove(start, start + size, "System RAM");
memblock_free(start, size);
memblock_remove(start, size);

arch_remove_memory(start, size);

Expand Down
8 changes: 8 additions & 0 deletions mm/page_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5060,6 +5060,10 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid,
{
unsigned long zone_start_pfn, zone_end_pfn;

/* When hotadd a new node, the node should be empty */
if (!node_start_pfn && !node_end_pfn)
return 0;

/* Get the start and end of the zone */
zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
Expand Down Expand Up @@ -5123,6 +5127,10 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
unsigned long zone_start_pfn, zone_end_pfn;

/* When hotadd a new node, the node should be empty */
if (!node_start_pfn && !node_end_pfn)
return 0;

zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);

Expand Down

0 comments on commit f9126ab

Please sign in to comment.