cpu/SMT: fix x86 link error without CONFIG_SYSFS

Message ID 20191210195614.786555-1-arnd@arndb.de
State New
Headers show
Series
  • cpu/SMT: fix x86 link error without CONFIG_SYSFS
Related show

Commit Message

Arnd Bergmann Dec. 10, 2019, 7:56 p.m.
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")
Cc: stable@vger.kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

---
 kernel/cpu.c | 143 ++++++++++++++++++++++++++-------------------------
 1 file changed, 72 insertions(+), 71 deletions(-)

-- 
2.20.0

Comments

Jiri Kosina Dec. 10, 2019, 8:12 p.m. | #1
On Tue, 10 Dec 2019, Arnd Bergmann wrote:

> When CONFIG_SYSFS is disabled, but CONFIG_HOTPLUG_SMT is enabled,

> the kernel fails to link:


I wonder where such kernels are running ... or I rather don't :)

> 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")


Reviewed-by: Jiri Kosina <jkosina@suse.cz>


Thanks for fixing my oversight.

-- 
Jiri Kosina
SUSE Labs
Jiri Kosina Dec. 20, 2019, 10:01 p.m. | #2
On Tue, 10 Dec 2019, Jiri Kosina wrote:

> > When CONFIG_SYSFS is disabled, but CONFIG_HOTPLUG_SMT is enabled,

> > the kernel fails to link:

> 

> I wonder where such kernels are running ... or I rather don't :)

> 

> > 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")

> 

> Reviewed-by: Jiri Kosina <jkosina@suse.cz>

> 

> Thanks for fixing my oversight.


Is anyone going to pick this up please?

Thanks,

-- 
Jiri Kosina
SUSE Labs

Patch

diff --git a/kernel/cpu.c b/kernel/cpu.c
index a59cc980adad..4dc279ed3b2d 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -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)