aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorYasunori Goto <y-goto@jp.fujitsu.com>2006-06-27 05:53:34 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-27 20:32:36 -0400
commit9af3c2dea3a3ae4248d81a70b556adfe1dc65d55 (patch)
treed39b4f7bd082d8a64ef31f6cf34a3b535f594fd0 /mm
parent3218ae14b1e3ee2ab81df30ed690c8e864d23316 (diff)
[PATCH] pgdat allocation for new node add (call pgdat allocation)
Add node-hot-add support to add_memory(). node hotadd uses this sequence. 1. allocate pgdat. 2. refresh NODE_DATA() 3. call free_area_init_node() to initialize 4. create sysfs entry 5. add memory (old add_memory()) 6. set node online 7. run kswapd for new node. (8). update zonelist after pages are onlined. (This is already merged in -mm due to update phase is difference.) Note: To make common function as much as possible, there is 2 changes from v2. - The old add_memory(), which is defiend by each archs, is renamed to arch_add_memory(). New add_memory becomes caller of arch dependent function as a common code. - This patch changes add_memory()'s interface From: add_memory(start, end) TO : add_memory(nid, start, end). It was cause of similar code that finding node id from physical address is inside of old add_memory() on each arch. In addition, acpi memory hotplug driver can find node id easier. In v2, it must walk DSDT'S _CRS by matching physical address to get the handle of its memory device, then get _PXM and node id. Because input is just physical address. However, in v3, the acpi driver can use handle to get _PXM and node id for the new memory device. It can pass just node id to add_memory(). Fix interface of arch_add_memory() is in next patche. Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Dave Hansen <haveblue@us.ibm.com> Cc: "Brown, Len" <len.brown@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memory_hotplug.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 6cdeabe9f6d4..83d37a401b3b 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -164,13 +164,65 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
164 return 0; 164 return 0;
165} 165}
166 166
167static pg_data_t *hotadd_new_pgdat(int nid, u64 start)
168{
169 struct pglist_data *pgdat;
170 unsigned long zones_size[MAX_NR_ZONES] = {0};
171 unsigned long zholes_size[MAX_NR_ZONES] = {0};
172 unsigned long start_pfn = start >> PAGE_SHIFT;
173
174 pgdat = arch_alloc_nodedata(nid);
175 if (!pgdat)
176 return NULL;
177
178 arch_refresh_nodedata(nid, pgdat);
179
180 /* we can use NODE_DATA(nid) from here */
181
182 /* init node's zones as empty zones, we don't have any present pages.*/
183 free_area_init_node(nid, pgdat, zones_size, start_pfn, zholes_size);
184
185 return pgdat;
186}
187
188static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
189{
190 arch_refresh_nodedata(nid, NULL);
191 arch_free_nodedata(pgdat);
192 return;
193}
194
167int add_memory(int nid, u64 start, u64 size) 195int add_memory(int nid, u64 start, u64 size)
168{ 196{
197 pg_data_t *pgdat = NULL;
198 int new_pgdat = 0;
169 int ret; 199 int ret;
170 200
201 if (!node_online(nid)) {
202 pgdat = hotadd_new_pgdat(nid, start);
203 if (!pgdat)
204 return -ENOMEM;
205 new_pgdat = 1;
206 ret = kswapd_run(nid);
207 if (ret)
208 goto error;
209 }
210
171 /* call arch's memory hotadd */ 211 /* call arch's memory hotadd */
172 ret = arch_add_memory(nid, start, size); 212 ret = arch_add_memory(nid, start, size);
173 213
214 if (ret < 0)
215 goto error;
216
217 /* we online node here. we have no error path from here. */
218 node_set_online(nid);
219
220 return ret;
221error:
222 /* rollback pgdat allocation and others */
223 if (new_pgdat)
224 rollback_node_hotadd(nid, pgdat);
225
174 return ret; 226 return ret;
175} 227}
176EXPORT_SYMBOL_GPL(add_memory); 228EXPORT_SYMBOL_GPL(add_memory);