Skip to content

Commit 83b8aa4

Browse files
vireshkJiri Slaby
authored andcommitted
cpufreq: remove sysfs files for CPUs which failed to come back after resume
commit 42f921a upstream. There are cases where cpufreq_add_dev() may fail for some CPUs during system resume. With the current code we will still have sysfs cpufreq files for those CPUs and struct cpufreq_policy would be already freed for them. Hence any operation on those sysfs files would result in kernel warnings. Example of problems resulting from resume errors (from Bjørn Mork): WARNING: CPU: 0 PID: 6055 at fs/sysfs/file.c:343 sysfs_open_file+0x77/0x212() missing sysfs attribute operations for kobject: (null) Modules linked in: [stripped as irrelevant] CPU: 0 PID: 6055 Comm: grep Tainted: G D 3.13.0-rc2 torvalds#153 Hardware name: LENOVO 2776LEG/2776LEG, BIOS 6EET55WW (3.15 ) 12/19/2011 0000000000000009 ffff8802327ebb78 ffffffff81380b0e 0000000000000006 ffff8802327ebbc8 ffff8802327ebbb8 ffffffff81038635 0000000000000000 ffffffff811823c7 ffff88021a19e688 ffff88021a19e688 ffff8802302f9310 Call Trace: [<ffffffff81380b0e>] dump_stack+0x55/0x76 [<ffffffff81038635>] warn_slowpath_common+0x7c/0x96 [<ffffffff811823c7>] ? sysfs_open_file+0x77/0x212 [<ffffffff810386e3>] warn_slowpath_fmt+0x41/0x43 [<ffffffff81182dec>] ? sysfs_get_active+0x6b/0x82 [<ffffffff81182382>] ? sysfs_open_file+0x32/0x212 [<ffffffff811823c7>] sysfs_open_file+0x77/0x212 [<ffffffff81182350>] ? sysfs_schedule_callback+0x1ac/0x1ac [<ffffffff81122562>] do_dentry_open+0x17c/0x257 [<ffffffff8112267e>] finish_open+0x41/0x4f [<ffffffff81130225>] do_last+0x80c/0x9ba [<ffffffff8112dbbd>] ? inode_permission+0x40/0x42 [<ffffffff81130606>] path_openat+0x233/0x4a1 [<ffffffff81130b7e>] do_filp_open+0x35/0x85 [<ffffffff8113b787>] ? __alloc_fd+0x172/0x184 [<ffffffff811232ea>] do_sys_open+0x6b/0xfa [<ffffffff811233a7>] SyS_openat+0xf/0x11 [<ffffffff8138c812>] system_call_fastpath+0x16/0x1b To fix this, remove those sysfs files or put the associated kobject in case of such errors. Also, to make it simple, remove the cpufreq sysfs links from all the CPUs (except for the policy->cpu) during suspend, as that operation won't result in a loss of sysfs file permissions and we can create those links during resume just fine. [js] no rwsem in 3.12 yet Fixes: 5302c3f ("cpufreq: Perform light-weight init/teardown during suspend/resume") Reported-and-tested-by: Bjørn Mork <[email protected]> Signed-off-by: Viresh Kumar <[email protected]> [rjw: Changelog] Signed-off-by: Rafael J. Wysocki <[email protected]> Signed-off-by: Jiri Slaby <[email protected]>
1 parent 85acace commit 83b8aa4

File tree

1 file changed

+31
-32
lines changed

1 file changed

+31
-32
lines changed

drivers/cpufreq/cpufreq.c

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -872,8 +872,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
872872

873873
#ifdef CONFIG_HOTPLUG_CPU
874874
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
875-
unsigned int cpu, struct device *dev,
876-
bool frozen)
875+
unsigned int cpu, struct device *dev)
877876
{
878877
int ret = 0, has_target = !!cpufreq_driver->target;
879878
unsigned long flags;
@@ -904,11 +903,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
904903
}
905904
}
906905

907-
/* Don't touch sysfs links during light-weight init */
908-
if (!frozen)
909-
ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
910-
911-
return ret;
906+
return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
912907
}
913908
#endif
914909

@@ -951,6 +946,27 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
951946
return NULL;
952947
}
953948

949+
static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
950+
{
951+
struct kobject *kobj;
952+
struct completion *cmp;
953+
954+
lock_policy_rwsem_read(policy->cpu);
955+
kobj = &policy->kobj;
956+
cmp = &policy->kobj_unregister;
957+
unlock_policy_rwsem_read(policy->cpu);
958+
kobject_put(kobj);
959+
960+
/*
961+
* We need to make sure that the underlying kobj is
962+
* actually not referenced anymore by anybody before we
963+
* proceed with unloading.
964+
*/
965+
pr_debug("waiting for dropping of refcount\n");
966+
wait_for_completion(cmp);
967+
pr_debug("wait complete\n");
968+
}
969+
954970
static void cpufreq_policy_free(struct cpufreq_policy *policy)
955971
{
956972
free_cpumask_var(policy->related_cpus);
@@ -1020,7 +1036,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
10201036
list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
10211037
if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
10221038
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
1023-
ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen);
1039+
ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev);
10241040
up_read(&cpufreq_rwsem);
10251041
return ret;
10261042
}
@@ -1119,7 +1135,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
11191135
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
11201136

11211137
err_set_policy_cpu:
1138+
if (frozen)
1139+
cpufreq_policy_put_kobj(policy);
11221140
cpufreq_policy_free(policy);
1141+
11231142
nomem_out:
11241143
up_read(&cpufreq_rwsem);
11251144

@@ -1141,18 +1160,14 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
11411160
}
11421161

11431162
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
1144-
unsigned int old_cpu, bool frozen)
1163+
unsigned int old_cpu)
11451164
{
11461165
struct device *cpu_dev;
11471166
int ret;
11481167

11491168
/* first sibling now owns the new sysfs dir */
11501169
cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
11511170

1152-
/* Don't touch sysfs files during light-weight tear-down */
1153-
if (frozen)
1154-
return cpu_dev->id;
1155-
11561171
sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
11571172
ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
11581173
if (ret) {
@@ -1220,7 +1235,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
12201235
sysfs_remove_link(&dev->kobj, "cpufreq");
12211236
} else if (cpus > 1) {
12221237

1223-
new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen);
1238+
new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
12241239
if (new_cpu >= 0) {
12251240
update_policy_cpu(policy, new_cpu);
12261241

@@ -1242,8 +1257,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
12421257
int ret;
12431258
unsigned long flags;
12441259
struct cpufreq_policy *policy;
1245-
struct kobject *kobj;
1246-
struct completion *cmp;
12471260

12481261
read_lock_irqsave(&cpufreq_driver_lock, flags);
12491262
policy = per_cpu(cpufreq_cpu_data, cpu);
@@ -1273,22 +1286,8 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
12731286
}
12741287
}
12751288

1276-
if (!frozen) {
1277-
lock_policy_rwsem_read(cpu);
1278-
kobj = &policy->kobj;
1279-
cmp = &policy->kobj_unregister;
1280-
unlock_policy_rwsem_read(cpu);
1281-
kobject_put(kobj);
1282-
1283-
/*
1284-
* We need to make sure that the underlying kobj is
1285-
* actually not referenced anymore by anybody before we
1286-
* proceed with unloading.
1287-
*/
1288-
pr_debug("waiting for dropping of refcount\n");
1289-
wait_for_completion(cmp);
1290-
pr_debug("wait complete\n");
1291-
}
1289+
if (!frozen)
1290+
cpufreq_policy_put_kobj(policy);
12921291

12931292
/*
12941293
* Perform the ->exit() even during light-weight tear-down,

0 commit comments

Comments
 (0)