aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/node.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/base/node.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/base/node.c')
-rw-r--r--drivers/base/node.c285
1 files changed, 209 insertions, 76 deletions
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 1fe5536d404f..057979a19eea 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -15,9 +15,13 @@
15#include <linux/cpu.h> 15#include <linux/cpu.h>
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/swap.h> 17#include <linux/swap.h>
18#include <linux/slab.h>
19
20static struct sysdev_class_attribute *node_state_attrs[];
18 21
19static struct sysdev_class node_class = { 22static struct sysdev_class node_class = {
20 .name = "node", 23 .name = "node",
24 .attrs = node_state_attrs,
21}; 25};
22 26
23 27
@@ -162,8 +166,11 @@ static ssize_t node_read_distance(struct sys_device * dev,
162 int len = 0; 166 int len = 0;
163 int i; 167 int i;
164 168
165 /* buf currently PAGE_SIZE, need ~4 chars per node */ 169 /*
166 BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2); 170 * buf is currently PAGE_SIZE in length and each node needs 4 chars
171 * at the most (distance + space or newline).
172 */
173 BUILD_BUG_ON(MAX_NUMNODES * 4 > PAGE_SIZE);
167 174
168 for_each_online_node(i) 175 for_each_online_node(i)
169 len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i)); 176 len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
@@ -173,6 +180,47 @@ static ssize_t node_read_distance(struct sys_device * dev,
173} 180}
174static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); 181static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
175 182
183#ifdef CONFIG_HUGETLBFS
184/*
185 * hugetlbfs per node attributes registration interface:
186 * When/if hugetlb[fs] subsystem initializes [sometime after this module],
187 * it will register its per node attributes for all online nodes with
188 * memory. It will also call register_hugetlbfs_with_node(), below, to
189 * register its attribute registration functions with this node driver.
190 * Once these hooks have been initialized, the node driver will call into
191 * the hugetlb module to [un]register attributes for hot-plugged nodes.
192 */
193static node_registration_func_t __hugetlb_register_node;
194static node_registration_func_t __hugetlb_unregister_node;
195
196static inline bool hugetlb_register_node(struct node *node)
197{
198 if (__hugetlb_register_node &&
199 node_state(node->sysdev.id, N_HIGH_MEMORY)) {
200 __hugetlb_register_node(node);
201 return true;
202 }
203 return false;
204}
205
206static inline void hugetlb_unregister_node(struct node *node)
207{
208 if (__hugetlb_unregister_node)
209 __hugetlb_unregister_node(node);
210}
211
212void register_hugetlbfs_with_node(node_registration_func_t doregister,
213 node_registration_func_t unregister)
214{
215 __hugetlb_register_node = doregister;
216 __hugetlb_unregister_node = unregister;
217}
218#else
219static inline void hugetlb_register_node(struct node *node) {}
220
221static inline void hugetlb_unregister_node(struct node *node) {}
222#endif
223
176 224
177/* 225/*
178 * register_node - Setup a sysfs device for a node. 226 * register_node - Setup a sysfs device for a node.
@@ -196,6 +244,8 @@ int register_node(struct node *node, int num, struct node *parent)
196 sysdev_create_file(&node->sysdev, &attr_distance); 244 sysdev_create_file(&node->sysdev, &attr_distance);
197 245
198 scan_unevictable_register_node(node); 246 scan_unevictable_register_node(node);
247
248 hugetlb_register_node(node);
199 } 249 }
200 return error; 250 return error;
201} 251}
@@ -216,6 +266,7 @@ void unregister_node(struct node *node)
216 sysdev_remove_file(&node->sysdev, &attr_distance); 266 sysdev_remove_file(&node->sysdev, &attr_distance);
217 267
218 scan_unevictable_unregister_node(node); 268 scan_unevictable_unregister_node(node);
269 hugetlb_unregister_node(node); /* no-op, if memoryless node */
219 270
220 sysdev_unregister(&node->sysdev); 271 sysdev_unregister(&node->sysdev);
221} 272}
@@ -227,26 +278,43 @@ struct node node_devices[MAX_NUMNODES];
227 */ 278 */
228int register_cpu_under_node(unsigned int cpu, unsigned int nid) 279int register_cpu_under_node(unsigned int cpu, unsigned int nid)
229{ 280{
230 if (node_online(nid)) { 281 int ret;
231 struct sys_device *obj = get_cpu_sysdev(cpu); 282 struct sys_device *obj;
232 if (!obj)
233 return 0;
234 return sysfs_create_link(&node_devices[nid].sysdev.kobj,
235 &obj->kobj,
236 kobject_name(&obj->kobj));
237 }
238 283
239 return 0; 284 if (!node_online(nid))
285 return 0;
286
287 obj = get_cpu_sysdev(cpu);
288 if (!obj)
289 return 0;
290
291 ret = sysfs_create_link(&node_devices[nid].sysdev.kobj,
292 &obj->kobj,
293 kobject_name(&obj->kobj));
294 if (ret)
295 return ret;
296
297 return sysfs_create_link(&obj->kobj,
298 &node_devices[nid].sysdev.kobj,
299 kobject_name(&node_devices[nid].sysdev.kobj));
240} 300}
241 301
242int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) 302int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
243{ 303{
244 if (node_online(nid)) { 304 struct sys_device *obj;
245 struct sys_device *obj = get_cpu_sysdev(cpu); 305
246 if (obj) 306 if (!node_online(nid))
247 sysfs_remove_link(&node_devices[nid].sysdev.kobj, 307 return 0;
248 kobject_name(&obj->kobj)); 308
249 } 309 obj = get_cpu_sysdev(cpu);
310 if (!obj)
311 return 0;
312
313 sysfs_remove_link(&node_devices[nid].sysdev.kobj,
314 kobject_name(&obj->kobj));
315 sysfs_remove_link(&obj->kobj,
316 kobject_name(&node_devices[nid].sysdev.kobj));
317
250 return 0; 318 return 0;
251} 319}
252 320
@@ -268,6 +336,7 @@ static int get_nid_for_pfn(unsigned long pfn)
268/* register memory section under specified node if it spans that node */ 336/* register memory section under specified node if it spans that node */
269int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) 337int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
270{ 338{
339 int ret;
271 unsigned long pfn, sect_start_pfn, sect_end_pfn; 340 unsigned long pfn, sect_start_pfn, sect_end_pfn;
272 341
273 if (!mem_blk) 342 if (!mem_blk)
@@ -284,9 +353,15 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
284 continue; 353 continue;
285 if (page_nid != nid) 354 if (page_nid != nid)
286 continue; 355 continue;
287 return sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj, 356 ret = sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj,
288 &mem_blk->sysdev.kobj, 357 &mem_blk->sysdev.kobj,
289 kobject_name(&mem_blk->sysdev.kobj)); 358 kobject_name(&mem_blk->sysdev.kobj));
359 if (ret)
360 return ret;
361
362 return sysfs_create_link_nowarn(&mem_blk->sysdev.kobj,
363 &node_devices[nid].sysdev.kobj,
364 kobject_name(&node_devices[nid].sysdev.kobj));
290 } 365 }
291 /* mem section does not span the specified node */ 366 /* mem section does not span the specified node */
292 return 0; 367 return 0;
@@ -295,12 +370,16 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
295/* unregister memory section under all nodes that it spans */ 370/* unregister memory section under all nodes that it spans */
296int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) 371int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
297{ 372{
298 nodemask_t unlinked_nodes; 373 NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
299 unsigned long pfn, sect_start_pfn, sect_end_pfn; 374 unsigned long pfn, sect_start_pfn, sect_end_pfn;
300 375
301 if (!mem_blk) 376 if (!mem_blk) {
377 NODEMASK_FREE(unlinked_nodes);
302 return -EFAULT; 378 return -EFAULT;
303 nodes_clear(unlinked_nodes); 379 }
380 if (!unlinked_nodes)
381 return -ENOMEM;
382 nodes_clear(*unlinked_nodes);
304 sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); 383 sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
305 sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; 384 sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
306 for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { 385 for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
@@ -311,11 +390,14 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
311 continue; 390 continue;
312 if (!node_online(nid)) 391 if (!node_online(nid))
313 continue; 392 continue;
314 if (node_test_and_set(nid, unlinked_nodes)) 393 if (node_test_and_set(nid, *unlinked_nodes))
315 continue; 394 continue;
316 sysfs_remove_link(&node_devices[nid].sysdev.kobj, 395 sysfs_remove_link(&node_devices[nid].sysdev.kobj,
317 kobject_name(&mem_blk->sysdev.kobj)); 396 kobject_name(&mem_blk->sysdev.kobj));
397 sysfs_remove_link(&mem_blk->sysdev.kobj,
398 kobject_name(&node_devices[nid].sysdev.kobj));
318 } 399 }
400 NODEMASK_FREE(unlinked_nodes);
319 return 0; 401 return 0;
320} 402}
321 403
@@ -345,9 +427,77 @@ static int link_mem_sections(int nid)
345 } 427 }
346 return err; 428 return err;
347} 429}
348#else 430
431#ifdef CONFIG_HUGETLBFS
432/*
433 * Handle per node hstate attribute [un]registration on transistions
434 * to/from memoryless state.
435 */
436static void node_hugetlb_work(struct work_struct *work)
437{
438 struct node *node = container_of(work, struct node, node_work);
439
440 /*
441 * We only get here when a node transitions to/from memoryless state.
442 * We can detect which transition occurred by examining whether the
443 * node has memory now. hugetlb_register_node() already check this
444 * so we try to register the attributes. If that fails, then the
445 * node has transitioned to memoryless, try to unregister the
446 * attributes.
447 */
448 if (!hugetlb_register_node(node))
449 hugetlb_unregister_node(node);
450}
451
452static void init_node_hugetlb_work(int nid)
453{
454 INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work);
455}
456
457static int node_memory_callback(struct notifier_block *self,
458 unsigned long action, void *arg)
459{
460 struct memory_notify *mnb = arg;
461 int nid = mnb->status_change_nid;
462
463 switch (action) {
464 case MEM_ONLINE:
465 case MEM_OFFLINE:
466 /*
467 * offload per node hstate [un]registration to a work thread
468 * when transitioning to/from memoryless state.
469 */
470 if (nid != NUMA_NO_NODE)
471 schedule_work(&node_devices[nid].node_work);
472 break;
473
474 case MEM_GOING_ONLINE:
475 case MEM_GOING_OFFLINE:
476 case MEM_CANCEL_ONLINE:
477 case MEM_CANCEL_OFFLINE:
478 default:
479 break;
480 }
481
482 return NOTIFY_OK;
483}
484#endif /* CONFIG_HUGETLBFS */
485#else /* !CONFIG_MEMORY_HOTPLUG_SPARSE */
486
349static int link_mem_sections(int nid) { return 0; } 487static int link_mem_sections(int nid) { return 0; }
350#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ 488#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
489
490#if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \
491 !defined(CONFIG_HUGETLBFS)
492static inline int node_memory_callback(struct notifier_block *self,
493 unsigned long action, void *arg)
494{
495 return NOTIFY_OK;
496}
497
498static void init_node_hugetlb_work(int nid) { }
499
500#endif
351 501
352int register_one_node(int nid) 502int register_one_node(int nid)
353{ 503{
@@ -371,6 +521,9 @@ int register_one_node(int nid)
371 521
372 /* link memory sections under this node */ 522 /* link memory sections under this node */
373 error = link_mem_sections(nid); 523 error = link_mem_sections(nid);
524
525 /* initialize work queue for memory hot plug */
526 init_node_hugetlb_work(nid);
374 } 527 }
375 528
376 return error; 529 return error;
@@ -398,75 +551,55 @@ static ssize_t print_nodes_state(enum node_states state, char *buf)
398 return n; 551 return n;
399} 552}
400 553
401static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf) 554struct node_attr {
402{ 555 struct sysdev_class_attribute attr;
403 return print_nodes_state(N_POSSIBLE, buf); 556 enum node_states state;
404} 557};
405
406static ssize_t print_nodes_online(struct sysdev_class *class, char *buf)
407{
408 return print_nodes_state(N_ONLINE, buf);
409}
410
411static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class,
412 char *buf)
413{
414 return print_nodes_state(N_NORMAL_MEMORY, buf);
415}
416 558
417static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf) 559static ssize_t show_node_state(struct sysdev_class *class,
560 struct sysdev_class_attribute *attr, char *buf)
418{ 561{
419 return print_nodes_state(N_CPU, buf); 562 struct node_attr *na = container_of(attr, struct node_attr, attr);
563 return print_nodes_state(na->state, buf);
420} 564}
421 565
422static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL); 566#define _NODE_ATTR(name, state) \
423static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL); 567 { _SYSDEV_CLASS_ATTR(name, 0444, show_node_state, NULL), state }
424static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory,
425 NULL);
426static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL);
427 568
569static struct node_attr node_state_attr[] = {
570 _NODE_ATTR(possible, N_POSSIBLE),
571 _NODE_ATTR(online, N_ONLINE),
572 _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY),
573 _NODE_ATTR(has_cpu, N_CPU),
428#ifdef CONFIG_HIGHMEM 574#ifdef CONFIG_HIGHMEM
429static ssize_t print_nodes_has_high_memory(struct sysdev_class *class, 575 _NODE_ATTR(has_high_memory, N_HIGH_MEMORY),
430 char *buf)
431{
432 return print_nodes_state(N_HIGH_MEMORY, buf);
433}
434
435static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory,
436 NULL);
437#endif 576#endif
577};
438 578
439struct sysdev_class_attribute *node_state_attr[] = { 579static struct sysdev_class_attribute *node_state_attrs[] = {
440 &attr_possible, 580 &node_state_attr[0].attr,
441 &attr_online, 581 &node_state_attr[1].attr,
442 &attr_has_normal_memory, 582 &node_state_attr[2].attr,
583 &node_state_attr[3].attr,
443#ifdef CONFIG_HIGHMEM 584#ifdef CONFIG_HIGHMEM
444 &attr_has_high_memory, 585 &node_state_attr[4].attr,
445#endif 586#endif
446 &attr_has_cpu, 587 NULL
447}; 588};
448 589
449static int node_states_init(void) 590#define NODE_CALLBACK_PRI 2 /* lower than SLAB */
450{
451 int i;
452 int err = 0;
453
454 for (i = 0; i < NR_NODE_STATES; i++) {
455 int ret;
456 ret = sysdev_class_create_file(&node_class, node_state_attr[i]);
457 if (!err)
458 err = ret;
459 }
460 return err;
461}
462
463static int __init register_node_type(void) 591static int __init register_node_type(void)
464{ 592{
465 int ret; 593 int ret;
466 594
595 BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES);
596 BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES);
597
467 ret = sysdev_class_register(&node_class); 598 ret = sysdev_class_register(&node_class);
468 if (!ret) 599 if (!ret) {
469 ret = node_states_init(); 600 hotplug_memory_notifier(node_memory_callback,
601 NODE_CALLBACK_PRI);
602 }
470 603
471 /* 604 /*
472 * Note: we're not going to unregister the node class if we fail 605 * Note: we're not going to unregister the node class if we fail