hugetlb: offload per node attribute registrations
[deliverable/linux.git] / drivers / base / node.c
index 9e218a6d4a5b68c05716a6cd137325cdc98abaf1..54e5d8eaf70e0d864096bc67b6ad28f21669bff0 100644 (file)
@@ -186,11 +186,14 @@ static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
 static node_registration_func_t __hugetlb_register_node;
 static node_registration_func_t __hugetlb_unregister_node;
 
-static inline void hugetlb_register_node(struct node *node)
+static inline bool hugetlb_register_node(struct node *node)
 {
        if (__hugetlb_register_node &&
-                       node_state(node->sysdev.id, N_HIGH_MEMORY))
+                       node_state(node->sysdev.id, N_HIGH_MEMORY)) {
                __hugetlb_register_node(node);
+               return true;
+       }
+       return false;
 }
 
 static inline void hugetlb_unregister_node(struct node *node)
@@ -387,10 +390,31 @@ static int link_mem_sections(int nid)
        return err;
 }
 
+#ifdef CONFIG_HUGETLBFS
 /*
  * Handle per node hstate attribute [un]registration on transistions
  * to/from memoryless state.
  */
+static void node_hugetlb_work(struct work_struct *work)
+{
+       struct node *node = container_of(work, struct node, node_work);
+
+       /*
+        * We only get here when a node transitions to/from memoryless state.
+        * We can detect which transition occurred by examining whether the
+        * node has memory now.  hugetlb_register_node() already check this
+        * so we try to register the attributes.  If that fails, then the
+        * node has transitioned to memoryless, try to unregister the
+        * attributes.
+        */
+       if (!hugetlb_register_node(node))
+               hugetlb_unregister_node(node);
+}
+
+static void init_node_hugetlb_work(int nid)
+{
+       INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work);
+}
 
 static int node_memory_callback(struct notifier_block *self,
                                unsigned long action, void *arg)
@@ -399,14 +423,16 @@ static int node_memory_callback(struct notifier_block *self,
        int nid = mnb->status_change_nid;
 
        switch (action) {
-       case MEM_ONLINE:    /* memory successfully brought online */
+       case MEM_ONLINE:
+       case MEM_OFFLINE:
+               /*
+                * offload per node hstate [un]registration to a work thread
+                * when transitioning to/from memoryless state.
+                */
                if (nid != NUMA_NO_NODE)
-                       hugetlb_register_node(&node_devices[nid]);
-               break;
-       case MEM_OFFLINE:   /* or offline */
-               if (nid != NUMA_NO_NODE)
-                       hugetlb_unregister_node(&node_devices[nid]);
+                       schedule_work(&node_devices[nid].node_work);
                break;
+
        case MEM_GOING_ONLINE:
        case MEM_GOING_OFFLINE:
        case MEM_CANCEL_ONLINE:
@@ -417,15 +443,23 @@ static int node_memory_callback(struct notifier_block *self,
 
        return NOTIFY_OK;
 }
-#else
+#endif /* CONFIG_HUGETLBFS */
+#else  /* !CONFIG_MEMORY_HOTPLUG_SPARSE */
+
 static int link_mem_sections(int nid) { return 0; }
+#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
 
+#if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \
+    !defined(CONFIG_HUGETLBFS)
 static inline int node_memory_callback(struct notifier_block *self,
                                unsigned long action, void *arg)
 {
        return NOTIFY_OK;
 }
-#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
+
+static void init_node_hugetlb_work(int nid) { }
+
+#endif
 
 int register_one_node(int nid)
 {
@@ -449,6 +483,9 @@ int register_one_node(int nid)
 
                /* link memory sections under this node */
                error = link_mem_sections(nid);
+
+               /* initialize work queue for memory hot plug */
+               init_node_hugetlb_work(nid);
        }
 
        return error;
This page took 0.024812 seconds and 5 git commands to generate.