Install the callbacks via the state machine, but do not invoke them as we
can initialize the node state without calling the callbacks on all online
CPUs.

start_shepherd_timer() is now called outside the get_online_cpus() block
which is safe as it only operates on cpu possible mask.

Cc: Andrew Morton <a...@linux-foundation.org>
Cc: Vlastimil Babka <vba...@suse.cz>
Cc: Mel Gorman <mgor...@techsingularity.net>
Cc: Johannes Weiner <han...@cmpxchg.org>
Cc: linux...@kvack.org
Signed-off-by: Sebastian Andrzej Siewior <bige...@linutronix.de>
Signed-off-by: Thomas Gleixner <t...@linutronix.de>
---
 include/linux/cpuhotplug.h |  1 +
 mm/vmstat.c                | 76 +++++++++++++++++++++-------------------------
 2 files changed, 36 insertions(+), 41 deletions(-)

diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 18bcfeb2463e..4ebd1bc27f8d 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -20,6 +20,7 @@ enum cpuhp_state {
        CPUHP_VIRT_NET_DEAD,
        CPUHP_SLUB_DEAD,
        CPUHP_MM_WRITEBACK_DEAD,
+       CPUHP_MM_VMSTAT_DEAD,
        CPUHP_SOFTIRQ_DEAD,
        CPUHP_NET_MVNETA_DEAD,
        CPUHP_CPUIDLE_DEAD,
diff --git a/mm/vmstat.c b/mm/vmstat.c
index b96dcec7e7d7..dfe3cb9f2c36 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1726,64 +1726,58 @@ static void __init init_cpu_node_state(void)
                node_set_state(node, N_CPU);
 }
 
-static void vmstat_cpu_dead(int node)
+static int vmstat_cpu_online(unsigned int cpu)
+{
+       refresh_zone_stat_thresholds();
+       node_set_state(cpu_to_node(cpu), N_CPU);
+       return 0;
+}
+
+static int vmstat_cpu_down_prep(unsigned int cpu)
+{
+       cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
+       return 0;
+}
+
+static int vmstat_cpu_dead(unsigned int cpu)
 {
        const struct cpumask *node_cpus;
+       int node;
 
+       node = cpu_to_node(cpu);
+
+       refresh_zone_stat_thresholds();
        node_cpus = cpumask_of_node(node);
        if (cpumask_weight(node_cpus) > 0)
-               return;
+               return 0;
 
        node_clear_state(node, N_CPU);
+       return 0;
 }
 
-/*
- * Use the cpu notifier to insure that the thresholds are recalculated
- * when necessary.
- */
-static int vmstat_cpuup_callback(struct notifier_block *nfb,
-               unsigned long action,
-               void *hcpu)
-{
-       long cpu = (long)hcpu;
-
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               refresh_zone_stat_thresholds();
-               node_set_state(cpu_to_node(cpu), N_CPU);
-               break;
-       case CPU_DOWN_PREPARE:
-       case CPU_DOWN_PREPARE_FROZEN:
-               cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
-               break;
-       case CPU_DOWN_FAILED:
-       case CPU_DOWN_FAILED_FROZEN:
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               refresh_zone_stat_thresholds();
-               vmstat_cpu_dead(cpu_to_node(cpu));
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block vmstat_notifier =
-       { &vmstat_cpuup_callback, NULL, 0 };
 #endif
 
 static int __init setup_vmstat(void)
 {
 #ifdef CONFIG_SMP
-       cpu_notifier_register_begin();
-       __register_cpu_notifier(&vmstat_notifier);
+       int ret;
+
+       ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead",
+                                       NULL, vmstat_cpu_dead);
+       if (ret < 0)
+               pr_err("vmstat: failed to register 'dead' hotplug state\n");
+
+       ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "mm/vmstat:online",
+                                       vmstat_cpu_online,
+                                       vmstat_cpu_down_prep);
+       if (ret < 0)
+               pr_err("vmstat: failed to register 'online' hotplug state\n");
+
+       get_online_cpus();
        init_cpu_node_state();
+       put_online_cpus();
 
        start_shepherd_timer();
-       cpu_notifier_register_done();
 #endif
 #ifdef CONFIG_PROC_FS
        proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
-- 
2.10.2

Reply via email to