[PATCH]: Fix stale cpufreq_cpu_governor pointer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On an pre-F12 based Fedora system,

echo 0 > /sys/devices/system/cpu/cpu4/online

service cpuspeed stop

service cpupseed start

echo 1 > /sys/devices/system/cpu/cpu4/online

results in

BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<(null)>] (null)
PGD 409cab067 PUD 409c84067 PMD 0 
Oops: 0010 [#1] SMP 
last sysfs file: /sys/devices/system/cpu/cpu6/online
CPU 5 
Modules linked in: cpufreq_ondemand nfs fscache ipt_MASQUERADE iptable_nat nf_nat bridge stp llc nfsd lockd nfs_acl auth_rpcgss exportfs sunrpc xt_physdev ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 acpi_cpufreq freq_table dm_multipath i5k_amb hwmon ata_generic qla2xxx pata_acpi iTCO_wdt scsi_transport_fc bnx2 iTCO_vendor_support scsi_tgt i5000_edac ses ata_piix enclosure edac_core dcdbas pcspkr serio_raw joydev dm_snapshot dm_zero dm_mirror dm_region_hash dm_log dm_mod shpchp megaraid_sas radeon ttm drm_kms_helper drm i2c_algo_bit i2c_core [last unloaded: cpufreq_ondemand]
Pid: 5508, comm: bash Not tainted 2.6.32-rc5 #1 PowerEdge 1950
RIP: 0010:[<0000000000000000>]  [<(null)>] (null)
RSP: 0018:ffff88042c463a80  EFLAGS: 00010296
RAX: ffffffffa021c4a0 RBX: ffff88042ab39da8 RCX: 0000000000000006
RDX: ffffffff816afbb7 RSI: 0000000000000001 RDI: ffff88042ab39da8
RBP: ffff88042c463ab8 R08: 0000000000000001 R09: 00000000e531e4a0
R10: ffffffff81e9cb60 R11: ffff88042c463a48 R12: 0000000000000001
R13: 00000000ffffffea R14: 0000000000000000 R15: 00000000001daaa0
FS:  00007f3b46040700(0000) GS:ffff880043400000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000409ca8000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process bash (pid: 5508, threadinfo ffff88042c462000, task ffff88042227d940)
Stack:
 ffffffff813e2508 00000000002dc6c0 00000000e531e4a0 ffff88042c463ab8
<0> ffff88042ab39da8 ffff88042c463b18 0000000000000000 ffff88042c463af8
<0> ffffffff813e35b8 ffff88042c463af8 00000000e531e4a0 ffff88042ab39da8
Call Trace:
 [<ffffffff813e2508>] ? __cpufreq_governor+0x93/0xe7
 [<ffffffff813e35b8>] __cpufreq_set_policy+0x1bb/0x24d
 [<ffffffff813e37d2>] cpufreq_add_dev_interface+0x188/0x212
 [<ffffffff813e3cd7>] ? handle_update+0x0/0x57
 [<ffffffff813e442d>] cpufreq_add_dev+0x269/0x370
 [<ffffffff814c85a5>] cpufreq_cpu_callback+0x7b/0x9f
 [<ffffffff814d0e3a>] notifier_call_chain+0x72/0xba
 [<ffffffff81084b18>] raw_notifier_call_chain+0x22/0x38
 [<ffffffff814c69bb>] _cpu_up+0xef/0x152
 [<ffffffff814c6a88>] cpu_up+0x6a/0x8b
 [<ffffffff814b7ac1>] store_online+0x5b/0x96
 [<ffffffff8133229d>] sysdev_store+0x2e/0x44
 [<ffffffff81197471>] sysfs_write_file+0x105/0x155
 [<ffffffff811322ee>] vfs_write+0xb8/0x129
 [<ffffffff81132447>] sys_write+0x54/0x8c
 [<ffffffff81011e02>] system_call_fastpath+0x16/0x1b
Code:  Bad RIP value.
RIP  [<(null)>] (null)
 RSP <ffff88042c463a80>
CR2: 0000000000000000
---[ end trace b2117a324130d450 ]---

This happens because the per_cpu element cpufreq_cpu_governor becomes stale
after the cpuspeed service is stopped and the governor is unregistered.

1.  When a governor is unregistered, go through the cpufreq_cpu_governor values
and NULL out those corresponding to the governor.

2.  After a cpu is brought up, the CPUFREQ_DEFAULT_GOVERNOR is automatically
selected by the kernel.  However, it is possible that the governor being
used by the cpu's siblings is not the default governor.  In the hotplug case,
the other siblings should be queried in order to determine what they are using
as a governor, and then that governor should be used for the current cpu.

Signed-off-by: Prarit Bhargava <prarit@xxxxxxxxxx>

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2968ed6..4ac4237 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -769,13 +769,16 @@ static struct kobj_type ktype_cpufreq = {
 static int cpufreq_add_dev(struct sys_device *sys_dev)
 {
 	unsigned int cpu = sys_dev->id;
-	int ret = 0;
+	int ret = 0, found = 0;
 	struct cpufreq_policy new_policy;
 	struct cpufreq_policy *policy;
 	struct freq_attr **drv_attr;
 	struct sys_device *cpu_sys_dev;
 	unsigned long flags;
 	unsigned int j;
+#ifdef CONFIG_HOTPLUG_CPU
+	int sibling;
+#endif
 
 	if (cpu_is_offline(cpu))
 		return 0;
@@ -825,7 +828,19 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 	INIT_WORK(&policy->update, handle_update);
 
 	/* Set governor before ->init, so that driver could check it */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+#ifdef CONFIG_HOTPLUG_CPU
+	for_each_online_cpu(sibling) {
+		struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
+		if (cp && cp->governor &&
+		    (cpumask_test_cpu(cpu, cp->related_cpus))) {
+			policy->governor = cp->governor;
+			found = 1;
+			break;
+		}
+	}
+#endif
+	if (!found)
+		policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
 	 */
@@ -1550,9 +1565,22 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
 
 void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 {
+	int cpu;
+	struct cpufreq_governor * cg;
+
 	if (!governor)
 		return;
 
+#if CONFIG_HOTPLUG_CPU
+	for_each_present_cpu(cpu) {
+		if (cpu_online(cpu))
+			continue;
+		cg = per_cpu(cpufreq_cpu_governor, cpu);
+		if (cg && !strcmp(cg->name, governor->name))
+			per_cpu(cpufreq_cpu_governor, cpu) = NULL;
+	}
+#endif
+
 	mutex_lock(&cpufreq_governor_mutex);
 	list_del(&governor->governor_list);
 	mutex_unlock(&cpufreq_governor_mutex);
--
To unsubscribe from this list: send the line "unsubscribe cpufreq" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Devel]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Forum]     [Linux SCSI]

  Powered by Linux