diff options
Diffstat (limited to 'drivers/base/node.c')
| -rw-r--r-- | drivers/base/node.c | 85 | 
1 files changed, 55 insertions, 30 deletions
| diff --git a/drivers/base/node.c b/drivers/base/node.c index 508b80f6329b..50af16e68d98 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -761,14 +761,36 @@ static int __ref get_nid_for_pfn(unsigned long pfn)  	return pfn_to_nid(pfn);  } +static int do_register_memory_block_under_node(int nid, +					       struct memory_block *mem_blk) +{ +	int ret; + +	/* +	 * If this memory block spans multiple nodes, we only indicate +	 * the last processed node. +	 */ +	mem_blk->nid = nid; + +	ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj, +				       &mem_blk->dev.kobj, +				       kobject_name(&mem_blk->dev.kobj)); +	if (ret) +		return ret; + +	return sysfs_create_link_nowarn(&mem_blk->dev.kobj, +				&node_devices[nid]->dev.kobj, +				kobject_name(&node_devices[nid]->dev.kobj)); +} +  /* register memory section under specified node if it spans that node */ -static int register_mem_sect_under_node(struct memory_block *mem_blk, -					 void *arg) +static int register_mem_block_under_node_early(struct memory_block *mem_blk, +					       void *arg)  {  	unsigned long memory_block_pfns = memory_block_size_bytes() / PAGE_SIZE;  	unsigned long start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);  	unsigned long end_pfn = start_pfn + memory_block_pfns - 1; -	int ret, nid = *(int *)arg; +	int nid = *(int *)arg;  	unsigned long pfn;  	for (pfn = start_pfn; pfn <= end_pfn; pfn++) { @@ -785,39 +807,34 @@ static int register_mem_sect_under_node(struct memory_block *mem_blk,  		}  		/* -		 * We need to check if page belongs to nid only for the boot -		 * case, during hotplug we know that all pages in the memory -		 * block belong to the same node. -		 */ -		if (system_state == SYSTEM_BOOTING) { -			page_nid = get_nid_for_pfn(pfn); -			if (page_nid < 0) -				continue; -			if (page_nid != nid) -				continue; -		} - -		/* -		 * If this memory block spans multiple nodes, we only indicate -		 * the last processed node. +		 * We need to check if page belongs to nid only at the boot +		 * case because node's ranges can be interleaved.  		 */ -		mem_blk->nid = nid; - -		ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj, -					&mem_blk->dev.kobj, -					kobject_name(&mem_blk->dev.kobj)); -		if (ret) -			return ret; +		page_nid = get_nid_for_pfn(pfn); +		if (page_nid < 0) +			continue; +		if (page_nid != nid) +			continue; -		return sysfs_create_link_nowarn(&mem_blk->dev.kobj, -				&node_devices[nid]->dev.kobj, -				kobject_name(&node_devices[nid]->dev.kobj)); +		return do_register_memory_block_under_node(nid, mem_blk);  	}  	/* mem section does not span the specified node */  	return 0;  }  /* + * During hotplug we know that all pages in the memory block belong to the same + * node. + */ +static int register_mem_block_under_node_hotplug(struct memory_block *mem_blk, +						 void *arg) +{ +	int nid = *(int *)arg; + +	return do_register_memory_block_under_node(nid, mem_blk); +} + +/*   * Unregister a memory block device under the node it spans. Memory blocks   * with multiple nodes cannot be offlined and therefore also never be removed.   */ @@ -832,11 +849,19 @@ void unregister_memory_block_under_nodes(struct memory_block *mem_blk)  			  kobject_name(&node_devices[mem_blk->nid]->dev.kobj));  } -int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn) +int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn, +		      enum meminit_context context)  { +	walk_memory_blocks_func_t func; + +	if (context == MEMINIT_HOTPLUG) +		func = register_mem_block_under_node_hotplug; +	else +		func = register_mem_block_under_node_early; +  	return walk_memory_blocks(PFN_PHYS(start_pfn),  				  PFN_PHYS(end_pfn - start_pfn), (void *)&nid, -				  register_mem_sect_under_node); +				  func);  }  #ifdef CONFIG_HUGETLBFS |