Commit 39da08cb074cf19cb249832a2a955dfb28837e65

Authored by Lee Schermerhorn
Committed by Linus Torvalds
1 parent 4faf8d950e

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>

Showing 2 changed files with 52 additions and 10 deletions Side-by-side Diff

... ... @@ -186,11 +186,14 @@
186 186 static node_registration_func_t __hugetlb_register_node;
187 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 191 if (__hugetlb_register_node &&
192   - node_state(node->sysdev.id, N_HIGH_MEMORY))
  192 + node_state(node->sysdev.id, N_HIGH_MEMORY)) {
193 193 __hugetlb_register_node(node);
  194 + return true;
  195 + }
  196 + return false;
194 197 }
195 198  
196 199 static inline void hugetlb_unregister_node(struct node *node)
197 200  
198 201  
... ... @@ -387,11 +390,32 @@
387 390 return err;
388 391 }
389 392  
  393 +#ifdef CONFIG_HUGETLBFS
390 394 /*
391 395 * Handle per node hstate attribute [un]registration on transistions
392 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);
394 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 +}
  418 +
395 419 static int node_memory_callback(struct notifier_block *self,
396 420 unsigned long action, void *arg)
397 421 {
398 422  
399 423  
... ... @@ -399,14 +423,16 @@
399 423 int nid = mnb->status_change_nid;
400 424  
401 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 432 if (nid != NUMA_NO_NODE)
404   - hugetlb_register_node(&node_devices[nid]);
  433 + schedule_work(&node_devices[nid].node_work);
405 434 break;
406   - case MEM_OFFLINE: /* or offline */
407   - if (nid != NUMA_NO_NODE)
408   - hugetlb_unregister_node(&node_devices[nid]);
409   - break;
  435 +
410 436 case MEM_GOING_ONLINE:
411 437 case MEM_GOING_OFFLINE:
412 438 case MEM_CANCEL_ONLINE:
413 439  
414 440  
415 441  
416 442  
... ... @@ -417,16 +443,24 @@
417 443  
418 444 return NOTIFY_OK;
419 445 }
420   -#else
  446 +#endif /* CONFIG_HUGETLBFS */
  447 +#else /* !CONFIG_MEMORY_HOTPLUG_SPARSE */
  448 +
421 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 454 static inline int node_memory_callback(struct notifier_block *self,
424 455 unsigned long action, void *arg)
425 456 {
426 457 return NOTIFY_OK;
427 458 }
428   -#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
429 459  
  460 +static void init_node_hugetlb_work(int nid) { }
  461 +
  462 +#endif
  463 +
430 464 int register_one_node(int nid)
431 465 {
432 466 int error = 0;
... ... @@ -449,6 +483,9 @@
449 483  
450 484 /* link memory sections under this node */
451 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 491 return error;
include/linux/node.h
... ... @@ -21,9 +21,14 @@
21 21  
22 22 #include <linux/sysdev.h>
23 23 #include <linux/cpumask.h>
  24 +#include <linux/workqueue.h>
24 25  
25 26 struct node {
26 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  
29 34 struct memory_block;