@@ -124,16 +124,25 @@ enum {
#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
#ifdef CONFIG_HOTPLUG_CPU
extern int register_cpu_notifier(struct notifier_block *nb);
+extern int register_allcpu_notifier(struct notifier_block *nb,
+ bool replay_history, int (*history_setup)(void));
extern void unregister_cpu_notifier(struct notifier_block *nb);
#else
#ifndef MODULE
extern int register_cpu_notifier(struct notifier_block *nb);
+extern int register_allcpu_notifier(struct notifier_block *nb,
+ bool replay_history, int (*history_setup)(void));
#else
static inline int register_cpu_notifier(struct notifier_block *nb)
{
return 0;
}
+static inline int register_allcpu_notifier(struct notifier_block *nb,
+ bool replay_history, int (*history_setup)(void))
+{
+ return 0;
+}
#endif
static inline void unregister_cpu_notifier(struct notifier_block *nb)
@@ -155,6 +164,12 @@ static inline int register_cpu_notifier(struct notifier_block *nb)
return 0;
}
+static inline int register_allcpu_notifier(struct notifier_block *nb,
+ bool replay_history, int (*history_setup)(void))
+{
+ return 0;
+}
+
static inline void unregister_cpu_notifier(struct notifier_block *nb)
{
}
@@ -132,12 +132,56 @@ static void cpu_hotplug_done(void) {}
/* Need to know about CPUs going up/down? */
int __ref register_cpu_notifier(struct notifier_block *nb)
{
- int ret;
+ return register_allcpu_notifier(nb, false, NULL);
+}
+EXPORT_SYMBOL(register_cpu_notifier);
+
+int __ref register_allcpu_notifier(struct notifier_block *nb,
+ bool replay_history, int (*history_setup)(void))
+{
+ int cpu, ret = 0;
+
+ if (!replay_history && history_setup)
+ return -EINVAL;
+
cpu_maps_update_begin();
- ret = raw_notifier_chain_register(&cpu_chain, nb);
+ /*
+ * We don't race with CPU hotplug, because we just took the
+ * cpu_add_remove_lock.
+ */
+
+ if (!replay_history)
+ goto Register;
+
+ if (history_setup) {
+ /*
+ * The caller has a special setup routine to rewrite
+ * history as he desires. Just invoke it. Don't
+ * proceed with callback registration if this setup is
+ * unsuccessful.
+ */
+ ret = history_setup();
+ } else {
+ /*
+ * Fallback to the usual callback, if a special handler
+ * for past CPU hotplug events is not specified.
+ * In this case, we will replay only past CPU bring-up
+ * events.
+ */
+ for_each_online_cpu(cpu) {
+ nb->notifier_call(nb, CPU_UP_PREPARE, cpu);
+ nb->notifier_call(nb, CPU_ONLINE, cpu);
+ }
+ }
+
+ Register:
+ if (!ret)
+ ret = raw_notifier_chain_register(&cpu_chain, nb);
+
cpu_maps_update_done();
return ret;
}
+EXPORT_SYMBOL(register_allcpu_notifier);
static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
int *nr_calls)
@@ -161,7 +205,6 @@ static void cpu_notify_nofail(unsigned long val, void *v)
{
BUG_ON(cpu_notify(val, v));
}
-EXPORT_SYMBOL(register_cpu_notifier);
void __ref unregister_cpu_notifier(struct notifier_block *nb)
{