diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/node.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/drivers/base/node.c b/drivers/base/node.c index 9e218a6d4a5b..54e5d8eaf70e 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -186,11 +186,14 @@ static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); | |||
186 | static node_registration_func_t __hugetlb_register_node; | 186 | static node_registration_func_t __hugetlb_register_node; |
187 | static node_registration_func_t __hugetlb_unregister_node; | 187 | static node_registration_func_t __hugetlb_unregister_node; |
188 | 188 | ||
189 | static inline void hugetlb_register_node(struct node *node) | 189 | static inline bool hugetlb_register_node(struct node *node) |
190 | { | 190 | { |
191 | if (__hugetlb_register_node && | 191 | if (__hugetlb_register_node && |
192 | node_state(node->sysdev.id, N_HIGH_MEMORY)) | 192 | node_state(node->sysdev.id, N_HIGH_MEMORY)) { |
193 | __hugetlb_register_node(node); | 193 | __hugetlb_register_node(node); |
194 | return true; | ||
195 | } | ||
196 | return false; | ||
194 | } | 197 | } |
195 | 198 | ||
196 | static inline void hugetlb_unregister_node(struct node *node) | 199 | static inline void hugetlb_unregister_node(struct node *node) |
@@ -387,10 +390,31 @@ static int link_mem_sections(int nid) | |||
387 | return err; | 390 | return err; |
388 | } | 391 | } |
389 | 392 | ||
393 | #ifdef CONFIG_HUGETLBFS | ||
390 | /* | 394 | /* |
391 | * Handle per node hstate attribute [un]registration on transistions | 395 | * Handle per node hstate attribute [un]registration on transistions |
392 | * to/from memoryless state. | 396 | * to/from memoryless state. |
393 | */ | 397 | */ |
398 | static void node_hugetlb_work(struct work_struct *work) | ||
399 | { | ||
400 | struct node *node = container_of(work, struct node, node_work); | ||
401 | |||
402 | /* | ||
403 | * We only get here when a node transitions to/from memoryless state. | ||
404 | * We can detect which transition occurred by examining whether the | ||
405 | * node has memory now. hugetlb_register_node() already check this | ||
406 | * so we try to register the attributes. If that fails, then the | ||
407 | * node has transitioned to memoryless, try to unregister the | ||
408 | * attributes. | ||
409 | */ | ||
410 | if (!hugetlb_register_node(node)) | ||
411 | hugetlb_unregister_node(node); | ||
412 | } | ||
413 | |||
414 | static void init_node_hugetlb_work(int nid) | ||
415 | { | ||
416 | INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work); | ||
417 | } | ||
394 | 418 | ||
395 | static int node_memory_callback(struct notifier_block *self, | 419 | static int node_memory_callback(struct notifier_block *self, |
396 | unsigned long action, void *arg) | 420 | unsigned long action, void *arg) |
@@ -399,14 +423,16 @@ static int node_memory_callback(struct notifier_block *self, | |||
399 | int nid = mnb->status_change_nid; | 423 | int nid = mnb->status_change_nid; |
400 | 424 | ||
401 | switch (action) { | 425 | switch (action) { |
402 | case MEM_ONLINE: /* memory successfully brought online */ | 426 | case MEM_ONLINE: |
427 | case MEM_OFFLINE: | ||
428 | /* | ||
429 | * offload per node hstate [un]registration to a work thread | ||
430 | * when transitioning to/from memoryless state. | ||
431 | */ | ||
403 | if (nid != NUMA_NO_NODE) | 432 | if (nid != NUMA_NO_NODE) |
404 | hugetlb_register_node(&node_devices[nid]); | 433 | schedule_work(&node_devices[nid].node_work); |
405 | break; | ||
406 | case MEM_OFFLINE: /* or offline */ | ||
407 | if (nid != NUMA_NO_NODE) | ||
408 | hugetlb_unregister_node(&node_devices[nid]); | ||
409 | break; | 434 | break; |
435 | |||
410 | case MEM_GOING_ONLINE: | 436 | case MEM_GOING_ONLINE: |
411 | case MEM_GOING_OFFLINE: | 437 | case MEM_GOING_OFFLINE: |
412 | case MEM_CANCEL_ONLINE: | 438 | case MEM_CANCEL_ONLINE: |
@@ -417,15 +443,23 @@ static int node_memory_callback(struct notifier_block *self, | |||
417 | 443 | ||
418 | return NOTIFY_OK; | 444 | return NOTIFY_OK; |
419 | } | 445 | } |
420 | #else | 446 | #endif /* CONFIG_HUGETLBFS */ |
447 | #else /* !CONFIG_MEMORY_HOTPLUG_SPARSE */ | ||
448 | |||
421 | static int link_mem_sections(int nid) { return 0; } | 449 | static int link_mem_sections(int nid) { return 0; } |
450 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ | ||
422 | 451 | ||
452 | #if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \ | ||
453 | !defined(CONFIG_HUGETLBFS) | ||
423 | static inline int node_memory_callback(struct notifier_block *self, | 454 | static inline int node_memory_callback(struct notifier_block *self, |
424 | unsigned long action, void *arg) | 455 | unsigned long action, void *arg) |
425 | { | 456 | { |
426 | return NOTIFY_OK; | 457 | return NOTIFY_OK; |
427 | } | 458 | } |
428 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ | 459 | |
460 | static void init_node_hugetlb_work(int nid) { } | ||
461 | |||
462 | #endif | ||
429 | 463 | ||
430 | int register_one_node(int nid) | 464 | int register_one_node(int nid) |
431 | { | 465 | { |
@@ -449,6 +483,9 @@ int register_one_node(int nid) | |||
449 | 483 | ||
450 | /* link memory sections under this node */ | 484 | /* link memory sections under this node */ |
451 | error = link_mem_sections(nid); | 485 | error = link_mem_sections(nid); |
486 | |||
487 | /* initialize work queue for memory hot plug */ | ||
488 | init_node_hugetlb_work(nid); | ||
452 | } | 489 | } |
453 | 490 | ||
454 | return error; | 491 | return error; |