aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/node.c
diff options
context:
space:
mode:
authorLee Schermerhorn <lee.schermerhorn@hp.com>2009-12-14 20:58:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-15 11:53:13 -0500
commit39da08cb074cf19cb249832a2a955dfb28837e65 (patch)
treefded7c1757adb29aa682f86251addc66549b6907 /drivers/base/node.c
parent4faf8d950ec438c49ae4526b897c30f8a2cad741 (diff)
hugetlb: offload per node attribute registrations
Offload the registration and unregistration of per node hstate sysfs attributes to a worker thread rather than attempt the allocation/attachment or detachment/freeing of the attributes in the context of the memory hotplug handler. I don't know that this is absolutely required, but the registration can sleep in allocations and other mem hot plug handlers do it this way. If it turns out this is NOT required, we can drop this patch. N.B., Only tested build, boot, libhugetlbfs regression. i.e., no memory hotplug testing. Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Reviewed-by: Andi Kleen <andi@firstfloor.org> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Lee Schermerhorn <lee.schermerhorn@hp.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Randy Dunlap <randy.dunlap@oracle.com> Cc: Nishanth Aravamudan <nacc@us.ibm.com> Cc: David Rientjes <rientjes@google.com> Cc: Adam Litke <agl@us.ibm.com> Cc: Andy Whitcroft <apw@canonical.com> Cc: Eric Whitney <eric.whitney@hp.com> Cc: Christoph Lameter <cl@linux-foundation.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/base/node.c')
-rw-r--r--drivers/base/node.c57
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);
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;