diff options
Diffstat (limited to 'drivers/base/node.c')
| -rw-r--r-- | drivers/base/node.c | 86 |
1 files changed, 58 insertions, 28 deletions
diff --git a/drivers/base/node.c b/drivers/base/node.c index af1a177216f1..fac124a7e1c5 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
| @@ -227,7 +227,7 @@ static node_registration_func_t __hugetlb_unregister_node; | |||
| 227 | static inline bool hugetlb_register_node(struct node *node) | 227 | static inline bool hugetlb_register_node(struct node *node) |
| 228 | { | 228 | { |
| 229 | if (__hugetlb_register_node && | 229 | if (__hugetlb_register_node && |
| 230 | node_state(node->dev.id, N_HIGH_MEMORY)) { | 230 | node_state(node->dev.id, N_MEMORY)) { |
| 231 | __hugetlb_register_node(node); | 231 | __hugetlb_register_node(node); |
| 232 | return true; | 232 | return true; |
| 233 | } | 233 | } |
| @@ -252,6 +252,24 @@ static inline void hugetlb_register_node(struct node *node) {} | |||
| 252 | static inline void hugetlb_unregister_node(struct node *node) {} | 252 | static inline void hugetlb_unregister_node(struct node *node) {} |
| 253 | #endif | 253 | #endif |
| 254 | 254 | ||
| 255 | static void node_device_release(struct device *dev) | ||
| 256 | { | ||
| 257 | struct node *node = to_node(dev); | ||
| 258 | |||
| 259 | #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS) | ||
| 260 | /* | ||
| 261 | * We schedule the work only when a memory section is | ||
| 262 | * onlined/offlined on this node. When we come here, | ||
| 263 | * all the memory on this node has been offlined, | ||
| 264 | * so we won't enqueue new work to this work. | ||
| 265 | * | ||
| 266 | * The work is using node->node_work, so we should | ||
| 267 | * flush work before freeing the memory. | ||
| 268 | */ | ||
| 269 | flush_work(&node->node_work); | ||
| 270 | #endif | ||
| 271 | kfree(node); | ||
| 272 | } | ||
| 255 | 273 | ||
| 256 | /* | 274 | /* |
| 257 | * register_node - Setup a sysfs device for a node. | 275 | * register_node - Setup a sysfs device for a node. |
| @@ -259,12 +277,13 @@ static inline void hugetlb_unregister_node(struct node *node) {} | |||
| 259 | * | 277 | * |
| 260 | * Initialize and register the node device. | 278 | * Initialize and register the node device. |
| 261 | */ | 279 | */ |
| 262 | int register_node(struct node *node, int num, struct node *parent) | 280 | static int register_node(struct node *node, int num, struct node *parent) |
| 263 | { | 281 | { |
| 264 | int error; | 282 | int error; |
| 265 | 283 | ||
| 266 | node->dev.id = num; | 284 | node->dev.id = num; |
| 267 | node->dev.bus = &node_subsys; | 285 | node->dev.bus = &node_subsys; |
| 286 | node->dev.release = node_device_release; | ||
| 268 | error = device_register(&node->dev); | 287 | error = device_register(&node->dev); |
| 269 | 288 | ||
| 270 | if (!error){ | 289 | if (!error){ |
| @@ -306,7 +325,7 @@ void unregister_node(struct node *node) | |||
| 306 | device_unregister(&node->dev); | 325 | device_unregister(&node->dev); |
| 307 | } | 326 | } |
| 308 | 327 | ||
| 309 | struct node node_devices[MAX_NUMNODES]; | 328 | struct node *node_devices[MAX_NUMNODES]; |
| 310 | 329 | ||
| 311 | /* | 330 | /* |
| 312 | * register cpu under node | 331 | * register cpu under node |
| @@ -323,15 +342,15 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid) | |||
| 323 | if (!obj) | 342 | if (!obj) |
| 324 | return 0; | 343 | return 0; |
| 325 | 344 | ||
| 326 | ret = sysfs_create_link(&node_devices[nid].dev.kobj, | 345 | ret = sysfs_create_link(&node_devices[nid]->dev.kobj, |
| 327 | &obj->kobj, | 346 | &obj->kobj, |
| 328 | kobject_name(&obj->kobj)); | 347 | kobject_name(&obj->kobj)); |
| 329 | if (ret) | 348 | if (ret) |
| 330 | return ret; | 349 | return ret; |
| 331 | 350 | ||
| 332 | return sysfs_create_link(&obj->kobj, | 351 | return sysfs_create_link(&obj->kobj, |
| 333 | &node_devices[nid].dev.kobj, | 352 | &node_devices[nid]->dev.kobj, |
| 334 | kobject_name(&node_devices[nid].dev.kobj)); | 353 | kobject_name(&node_devices[nid]->dev.kobj)); |
| 335 | } | 354 | } |
| 336 | 355 | ||
| 337 | int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) | 356 | int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) |
| @@ -345,10 +364,10 @@ int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) | |||
| 345 | if (!obj) | 364 | if (!obj) |
| 346 | return 0; | 365 | return 0; |
| 347 | 366 | ||
| 348 | sysfs_remove_link(&node_devices[nid].dev.kobj, | 367 | sysfs_remove_link(&node_devices[nid]->dev.kobj, |
| 349 | kobject_name(&obj->kobj)); | 368 | kobject_name(&obj->kobj)); |
| 350 | sysfs_remove_link(&obj->kobj, | 369 | sysfs_remove_link(&obj->kobj, |
| 351 | kobject_name(&node_devices[nid].dev.kobj)); | 370 | kobject_name(&node_devices[nid]->dev.kobj)); |
| 352 | 371 | ||
| 353 | return 0; | 372 | return 0; |
| 354 | } | 373 | } |
| @@ -390,15 +409,15 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) | |||
| 390 | continue; | 409 | continue; |
| 391 | if (page_nid != nid) | 410 | if (page_nid != nid) |
| 392 | continue; | 411 | continue; |
| 393 | ret = sysfs_create_link_nowarn(&node_devices[nid].dev.kobj, | 412 | ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj, |
| 394 | &mem_blk->dev.kobj, | 413 | &mem_blk->dev.kobj, |
| 395 | kobject_name(&mem_blk->dev.kobj)); | 414 | kobject_name(&mem_blk->dev.kobj)); |
| 396 | if (ret) | 415 | if (ret) |
| 397 | return ret; | 416 | return ret; |
| 398 | 417 | ||
| 399 | return sysfs_create_link_nowarn(&mem_blk->dev.kobj, | 418 | return sysfs_create_link_nowarn(&mem_blk->dev.kobj, |
| 400 | &node_devices[nid].dev.kobj, | 419 | &node_devices[nid]->dev.kobj, |
| 401 | kobject_name(&node_devices[nid].dev.kobj)); | 420 | kobject_name(&node_devices[nid]->dev.kobj)); |
| 402 | } | 421 | } |
| 403 | /* mem section does not span the specified node */ | 422 | /* mem section does not span the specified node */ |
| 404 | return 0; | 423 | return 0; |
| @@ -431,10 +450,10 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, | |||
| 431 | continue; | 450 | continue; |
| 432 | if (node_test_and_set(nid, *unlinked_nodes)) | 451 | if (node_test_and_set(nid, *unlinked_nodes)) |
| 433 | continue; | 452 | continue; |
| 434 | sysfs_remove_link(&node_devices[nid].dev.kobj, | 453 | sysfs_remove_link(&node_devices[nid]->dev.kobj, |
| 435 | kobject_name(&mem_blk->dev.kobj)); | 454 | kobject_name(&mem_blk->dev.kobj)); |
| 436 | sysfs_remove_link(&mem_blk->dev.kobj, | 455 | sysfs_remove_link(&mem_blk->dev.kobj, |
| 437 | kobject_name(&node_devices[nid].dev.kobj)); | 456 | kobject_name(&node_devices[nid]->dev.kobj)); |
| 438 | } | 457 | } |
| 439 | NODEMASK_FREE(unlinked_nodes); | 458 | NODEMASK_FREE(unlinked_nodes); |
| 440 | return 0; | 459 | return 0; |
| @@ -500,7 +519,7 @@ static void node_hugetlb_work(struct work_struct *work) | |||
| 500 | 519 | ||
| 501 | static void init_node_hugetlb_work(int nid) | 520 | static void init_node_hugetlb_work(int nid) |
| 502 | { | 521 | { |
| 503 | INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work); | 522 | INIT_WORK(&node_devices[nid]->node_work, node_hugetlb_work); |
| 504 | } | 523 | } |
| 505 | 524 | ||
| 506 | static int node_memory_callback(struct notifier_block *self, | 525 | static int node_memory_callback(struct notifier_block *self, |
| @@ -517,7 +536,7 @@ static int node_memory_callback(struct notifier_block *self, | |||
| 517 | * when transitioning to/from memoryless state. | 536 | * when transitioning to/from memoryless state. |
| 518 | */ | 537 | */ |
| 519 | if (nid != NUMA_NO_NODE) | 538 | if (nid != NUMA_NO_NODE) |
| 520 | schedule_work(&node_devices[nid].node_work); | 539 | schedule_work(&node_devices[nid]->node_work); |
| 521 | break; | 540 | break; |
| 522 | 541 | ||
| 523 | case MEM_GOING_ONLINE: | 542 | case MEM_GOING_ONLINE: |
| @@ -558,9 +577,13 @@ int register_one_node(int nid) | |||
| 558 | struct node *parent = NULL; | 577 | struct node *parent = NULL; |
| 559 | 578 | ||
| 560 | if (p_node != nid) | 579 | if (p_node != nid) |
| 561 | parent = &node_devices[p_node]; | 580 | parent = node_devices[p_node]; |
| 581 | |||
| 582 | node_devices[nid] = kzalloc(sizeof(struct node), GFP_KERNEL); | ||
| 583 | if (!node_devices[nid]) | ||
| 584 | return -ENOMEM; | ||
| 562 | 585 | ||
| 563 | error = register_node(&node_devices[nid], nid, parent); | 586 | error = register_node(node_devices[nid], nid, parent); |
| 564 | 587 | ||
| 565 | /* link cpu under this node */ | 588 | /* link cpu under this node */ |
| 566 | for_each_present_cpu(cpu) { | 589 | for_each_present_cpu(cpu) { |
| @@ -581,7 +604,8 @@ int register_one_node(int nid) | |||
| 581 | 604 | ||
| 582 | void unregister_one_node(int nid) | 605 | void unregister_one_node(int nid) |
| 583 | { | 606 | { |
| 584 | unregister_node(&node_devices[nid]); | 607 | unregister_node(node_devices[nid]); |
| 608 | node_devices[nid] = NULL; | ||
| 585 | } | 609 | } |
| 586 | 610 | ||
| 587 | /* | 611 | /* |
| @@ -614,23 +638,29 @@ static ssize_t show_node_state(struct device *dev, | |||
| 614 | { __ATTR(name, 0444, show_node_state, NULL), state } | 638 | { __ATTR(name, 0444, show_node_state, NULL), state } |
| 615 | 639 | ||
| 616 | static struct node_attr node_state_attr[] = { | 640 | static struct node_attr node_state_attr[] = { |
| 617 | _NODE_ATTR(possible, N_POSSIBLE), | 641 | [N_POSSIBLE] = _NODE_ATTR(possible, N_POSSIBLE), |
| 618 | _NODE_ATTR(online, N_ONLINE), | 642 | [N_ONLINE] = _NODE_ATTR(online, N_ONLINE), |
| 619 | _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY), | 643 | [N_NORMAL_MEMORY] = _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY), |
| 620 | _NODE_ATTR(has_cpu, N_CPU), | ||
| 621 | #ifdef CONFIG_HIGHMEM | 644 | #ifdef CONFIG_HIGHMEM |
| 622 | _NODE_ATTR(has_high_memory, N_HIGH_MEMORY), | 645 | [N_HIGH_MEMORY] = _NODE_ATTR(has_high_memory, N_HIGH_MEMORY), |
| 623 | #endif | 646 | #endif |
| 647 | #ifdef CONFIG_MOVABLE_NODE | ||
| 648 | [N_MEMORY] = _NODE_ATTR(has_memory, N_MEMORY), | ||
| 649 | #endif | ||
| 650 | [N_CPU] = _NODE_ATTR(has_cpu, N_CPU), | ||
| 624 | }; | 651 | }; |
| 625 | 652 | ||
| 626 | static struct attribute *node_state_attrs[] = { | 653 | static struct attribute *node_state_attrs[] = { |
| 627 | &node_state_attr[0].attr.attr, | 654 | &node_state_attr[N_POSSIBLE].attr.attr, |
| 628 | &node_state_attr[1].attr.attr, | 655 | &node_state_attr[N_ONLINE].attr.attr, |
| 629 | &node_state_attr[2].attr.attr, | 656 | &node_state_attr[N_NORMAL_MEMORY].attr.attr, |
| 630 | &node_state_attr[3].attr.attr, | ||
| 631 | #ifdef CONFIG_HIGHMEM | 657 | #ifdef CONFIG_HIGHMEM |
| 632 | &node_state_attr[4].attr.attr, | 658 | &node_state_attr[N_HIGH_MEMORY].attr.attr, |
| 659 | #endif | ||
| 660 | #ifdef CONFIG_MOVABLE_NODE | ||
| 661 | &node_state_attr[N_MEMORY].attr.attr, | ||
| 633 | #endif | 662 | #endif |
| 663 | &node_state_attr[N_CPU].attr.attr, | ||
| 634 | NULL | 664 | NULL |
| 635 | }; | 665 | }; |
| 636 | 666 | ||
