aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/node.c57
-rw-r--r--include/linux/node.h5
2 files changed, 52 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);
186static node_registration_func_t __hugetlb_register_node; 186static node_registration_func_t __hugetlb_register_node;
187static node_registration_func_t __hugetlb_unregister_node; 187static node_registration_func_t __hugetlb_unregister_node;
188 188
189static inline void hugetlb_register_node(struct node *node) 189static 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
196static inline void hugetlb_unregister_node(struct node *node) 199static 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 */
398static 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
414static void init_node_hugetlb_work(int nid)
415{
416 INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work);
417}
394 418
395static int node_memory_callback(struct notifier_block *self, 419static 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
421static int link_mem_sections(int nid) { return 0; } 449static 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)
423static inline int node_memory_callback(struct notifier_block *self, 454static 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
460static void init_node_hugetlb_work(int nid) { }
461
462#endif
429 463
430int register_one_node(int nid) 464int 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;
diff --git a/include/linux/node.h b/include/linux/node.h
index dae1521e1f05..06292dac3eab 100644
--- a/include/linux/node.h
+++ b/include/linux/node.h
@@ -21,9 +21,14 @@
21 21
22#include <linux/sysdev.h> 22#include <linux/sysdev.h>
23#include <linux/cpumask.h> 23#include <linux/cpumask.h>
24#include <linux/workqueue.h>
24 25
25struct node { 26struct node {
26 struct sys_device sysdev; 27 struct sys_device sysdev;
28
29#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS)
30 struct work_struct node_work;
31#endif
27}; 32};
28 33
29struct memory_block; 34struct memory_block;