cpu/SMT: Fix x86 link error without CONFIG_SYSFS
authorArnd Bergmann <arnd@arndb.de>
Tue, 10 Dec 2019 19:56:04 +0000 (20:56 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Jan 2020 07:22:36 +0000 (08:22 +0100)
commit dc8d37ed304eeeea47e65fb9edc1c6c8b0093386 upstream.

When CONFIG_SYSFS is disabled, but CONFIG_HOTPLUG_SMT is enabled,
the kernel fails to link:

arch/x86/power/cpu.o: In function `hibernate_resume_nonboot_cpu_disable':
(.text+0x38d): undefined reference to `cpuhp_smt_enable'
arch/x86/power/hibernate.o: In function `arch_resume_nosmt':
hibernate.c:(.text+0x291): undefined reference to `cpuhp_smt_enable'
hibernate.c:(.text+0x29c): undefined reference to `cpuhp_smt_disable'

Move the exported functions out of the #ifdef section into its
own with the correct conditions.

The patch that caused this is marked for stable backports, so
this one may need to be backported as well.

Fixes: ec527c318036 ("x86/power: Fix 'nosmt' vs hibernation triple fault during resume")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20191210195614.786555-1-arnd@arndb.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
kernel/cpu.c

index e2cad3e..1168254 100644 (file)
@@ -1909,6 +1909,78 @@ void __cpuhp_remove_state(enum cpuhp_state state, bool invoke)
 }
 EXPORT_SYMBOL(__cpuhp_remove_state);
 
+#ifdef CONFIG_HOTPLUG_SMT
+static void cpuhp_offline_cpu_device(unsigned int cpu)
+{
+       struct device *dev = get_cpu_device(cpu);
+
+       dev->offline = true;
+       /* Tell user space about the state change */
+       kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+}
+
+static void cpuhp_online_cpu_device(unsigned int cpu)
+{
+       struct device *dev = get_cpu_device(cpu);
+
+       dev->offline = false;
+       /* Tell user space about the state change */
+       kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+}
+
+int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
+{
+       int cpu, ret = 0;
+
+       cpu_maps_update_begin();
+       for_each_online_cpu(cpu) {
+               if (topology_is_primary_thread(cpu))
+                       continue;
+               ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);
+               if (ret)
+                       break;
+               /*
+                * As this needs to hold the cpu maps lock it's impossible
+                * to call device_offline() because that ends up calling
+                * cpu_down() which takes cpu maps lock. cpu maps lock
+                * needs to be held as this might race against in kernel
+                * abusers of the hotplug machinery (thermal management).
+                *
+                * So nothing would update device:offline state. That would
+                * leave the sysfs entry stale and prevent onlining after
+                * smt control has been changed to 'off' again. This is
+                * called under the sysfs hotplug lock, so it is properly
+                * serialized against the regular offline usage.
+                */
+               cpuhp_offline_cpu_device(cpu);
+       }
+       if (!ret)
+               cpu_smt_control = ctrlval;
+       cpu_maps_update_done();
+       return ret;
+}
+
+int cpuhp_smt_enable(void)
+{
+       int cpu, ret = 0;
+
+       cpu_maps_update_begin();
+       cpu_smt_control = CPU_SMT_ENABLED;
+       for_each_present_cpu(cpu) {
+               /* Skip online CPUs and CPUs on offline nodes */
+               if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
+                       continue;
+               ret = _cpu_up(cpu, 0, CPUHP_ONLINE);
+               if (ret)
+                       break;
+               /* See comment in cpuhp_smt_disable() */
+               cpuhp_online_cpu_device(cpu);
+       }
+       cpu_maps_update_done();
+       return ret;
+}
+#endif
+
 #if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU)
 static ssize_t show_cpuhp_state(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -2063,77 +2135,6 @@ static const struct attribute_group cpuhp_cpu_root_attr_group = {
 
 #ifdef CONFIG_HOTPLUG_SMT
 
-static void cpuhp_offline_cpu_device(unsigned int cpu)
-{
-       struct device *dev = get_cpu_device(cpu);
-
-       dev->offline = true;
-       /* Tell user space about the state change */
-       kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
-}
-
-static void cpuhp_online_cpu_device(unsigned int cpu)
-{
-       struct device *dev = get_cpu_device(cpu);
-
-       dev->offline = false;
-       /* Tell user space about the state change */
-       kobject_uevent(&dev->kobj, KOBJ_ONLINE);
-}
-
-int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
-{
-       int cpu, ret = 0;
-
-       cpu_maps_update_begin();
-       for_each_online_cpu(cpu) {
-               if (topology_is_primary_thread(cpu))
-                       continue;
-               ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);
-               if (ret)
-                       break;
-               /*
-                * As this needs to hold the cpu maps lock it's impossible
-                * to call device_offline() because that ends up calling
-                * cpu_down() which takes cpu maps lock. cpu maps lock
-                * needs to be held as this might race against in kernel
-                * abusers of the hotplug machinery (thermal management).
-                *
-                * So nothing would update device:offline state. That would
-                * leave the sysfs entry stale and prevent onlining after
-                * smt control has been changed to 'off' again. This is
-                * called under the sysfs hotplug lock, so it is properly
-                * serialized against the regular offline usage.
-                */
-               cpuhp_offline_cpu_device(cpu);
-       }
-       if (!ret)
-               cpu_smt_control = ctrlval;
-       cpu_maps_update_done();
-       return ret;
-}
-
-int cpuhp_smt_enable(void)
-{
-       int cpu, ret = 0;
-
-       cpu_maps_update_begin();
-       cpu_smt_control = CPU_SMT_ENABLED;
-       for_each_present_cpu(cpu) {
-               /* Skip online CPUs and CPUs on offline nodes */
-               if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
-                       continue;
-               ret = _cpu_up(cpu, 0, CPUHP_ONLINE);
-               if (ret)
-                       break;
-               /* See comment in cpuhp_smt_disable() */
-               cpuhp_online_cpu_device(cpu);
-       }
-       cpu_maps_update_done();
-       return ret;
-}
-
-
 static ssize_t
 __store_smt_control(struct device *dev, struct device_attribute *attr,
                    const char *buf, size_t count)