Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cpufreq: Avoid attempts to create duplicate symbolic links

After commit 87549141d516 (cpufreq: Stop migrating sysfs files on
hotplug) there is a problem with CPUs that share cpufreq policy
objects with other CPUs and are initially offline.

Say CPU1 shares a policy with CPU0 which is online and is registered
first. As part of the registration process, cpufreq_add_dev() is
called for it. It creates the policy object and a symbolic link
to it from the CPU1's sysfs directory. If CPU1 is registered
subsequently and it is offline at that time, cpufreq_add_dev() will
attempt to create a symbolic link to the policy object for it, but
that link is present already, so a warning about that will be
triggered.

To avoid that warning, make cpufreq use an additional CPU mask
containing related CPUs that are actually present for each policy
object. That mask is initialized when the policy object is populated
after its creation (for the first online CPU using it) and it includes
CPUs from the "policy CPUs" mask returned by the cpufreq driver's
->init() callback that are physically present at that time. Symbolic
links to the policy are created only for the CPUs in that mask.

If cpufreq_add_dev() is invoked for an offline CPU, it checks the
new mask and only creates the symlink if the CPU was not in it (the
CPU is added to the mask at the same time).

In turn, cpufreq_remove_dev() drops the given CPU from the new mask,
removes its symlink to the policy object and returns, unless it is
the CPU owning the policy object. In that case, the policy object
is moved to a new CPU's sysfs directory or deleted if the CPU being
removed was the last user of the policy.

While at it, notice that cpufreq_remove_dev() can't fail, because
its return value is ignored, so make it ignore return values from
__cpufreq_remove_dev_prepare() and __cpufreq_remove_dev_finish()
and prevent these functions from aborting on errors returned by
__cpufreq_governor(). Also drop the now unused sif argument from
them.

Fixes: 87549141d516 (cpufreq: Stop migrating sysfs files on hotplug)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reported-and-tested-by: Russell King <linux@arm.linux.org.uk>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

+56 -53
+55 -53
drivers/cpufreq/cpufreq.c
··· 1002 1002 int ret = 0; 1003 1003 1004 1004 /* Some related CPUs might not be present (physically hotplugged) */ 1005 - for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) { 1005 + for_each_cpu(j, policy->real_cpus) { 1006 1006 if (j == policy->kobj_cpu) 1007 1007 continue; 1008 1008 ··· 1019 1019 unsigned int j; 1020 1020 1021 1021 /* Some related CPUs might not be present (physically hotplugged) */ 1022 - for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) { 1022 + for_each_cpu(j, policy->real_cpus) { 1023 1023 if (j == policy->kobj_cpu) 1024 1024 continue; 1025 1025 ··· 1163 1163 if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) 1164 1164 goto err_free_cpumask; 1165 1165 1166 + if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL)) 1167 + goto err_free_rcpumask; 1168 + 1166 1169 ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &dev->kobj, 1167 1170 "cpufreq"); 1168 1171 if (ret) { 1169 1172 pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret); 1170 - goto err_free_rcpumask; 1173 + goto err_free_real_cpus; 1171 1174 } 1172 1175 1173 1176 INIT_LIST_HEAD(&policy->policy_list); ··· 1187 1184 1188 1185 return policy; 1189 1186 1187 + err_free_real_cpus: 1188 + free_cpumask_var(policy->real_cpus); 1190 1189 err_free_rcpumask: 1191 1190 free_cpumask_var(policy->related_cpus); 1192 1191 err_free_cpumask: ··· 1239 1234 write_unlock_irqrestore(&cpufreq_driver_lock, flags); 1240 1235 1241 1236 cpufreq_policy_put_kobj(policy, notify); 1237 + free_cpumask_var(policy->real_cpus); 1242 1238 free_cpumask_var(policy->related_cpus); 1243 1239 free_cpumask_var(policy->cpus); 1244 1240 kfree(policy); ··· 1264 1258 1265 1259 pr_debug("adding CPU %u\n", cpu); 1266 1260 1267 - /* 1268 - * Only possible if 'cpu' wasn't physically present earlier and we are 1269 - * here from subsys_interface add callback. A hotplug notifier will 1270 - * follow and we will handle it like logical CPU hotplug then. For now, 1271 - * just create the sysfs link. 1272 - */ 1273 - if (cpu_is_offline(cpu)) 1274 - return add_cpu_dev_symlink(per_cpu(cpufreq_cpu_data, cpu), cpu); 1261 + if (cpu_is_offline(cpu)) { 1262 + /* 1263 + * Only possible if we are here from the subsys_interface add 1264 + * callback. A hotplug notifier will follow and we will handle 1265 + * it as CPU online then. For now, just create the sysfs link, 1266 + * unless there is no policy or the link is already present. 1267 + */ 1268 + policy = per_cpu(cpufreq_cpu_data, cpu); 1269 + return policy && !cpumask_test_and_set_cpu(cpu, policy->real_cpus) 1270 + ? add_cpu_dev_symlink(policy, cpu) : 0; 1271 + } 1275 1272 1276 1273 if (!down_read_trylock(&cpufreq_rwsem)) 1277 1274 return 0; ··· 1315 1306 1316 1307 /* related cpus should atleast have policy->cpus */ 1317 1308 cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); 1309 + 1310 + /* Remember which CPUs have been present at the policy creation time. */ 1311 + if (!recover_policy) 1312 + cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask); 1318 1313 1319 1314 /* 1320 1315 * affected cpus must always be the one, which are online. We aren't ··· 1433 1420 return ret; 1434 1421 } 1435 1422 1436 - static int __cpufreq_remove_dev_prepare(struct device *dev, 1437 - struct subsys_interface *sif) 1423 + static int __cpufreq_remove_dev_prepare(struct device *dev) 1438 1424 { 1439 1425 unsigned int cpu = dev->id; 1440 1426 int ret = 0; ··· 1449 1437 1450 1438 if (has_target()) { 1451 1439 ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 1452 - if (ret) { 1440 + if (ret) 1453 1441 pr_err("%s: Failed to stop governor\n", __func__); 1454 - return ret; 1455 - } 1456 1442 } 1457 1443 1458 1444 down_write(&policy->rwsem); ··· 1483 1473 return ret; 1484 1474 } 1485 1475 1486 - static int __cpufreq_remove_dev_finish(struct device *dev, 1487 - struct subsys_interface *sif) 1476 + static int __cpufreq_remove_dev_finish(struct device *dev) 1488 1477 { 1489 1478 unsigned int cpu = dev->id; 1490 1479 int ret; ··· 1501 1492 /* If cpu is last user of policy, free policy */ 1502 1493 if (has_target()) { 1503 1494 ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); 1504 - if (ret) { 1495 + if (ret) 1505 1496 pr_err("%s: Failed to exit governor\n", __func__); 1506 - return ret; 1507 - } 1508 1497 } 1509 1498 1510 1499 /* ··· 1512 1505 */ 1513 1506 if (cpufreq_driver->exit) 1514 1507 cpufreq_driver->exit(policy); 1515 - 1516 - /* Free the policy only if the driver is getting removed. */ 1517 - if (sif) 1518 - cpufreq_policy_free(policy, true); 1519 1508 1520 1509 return 0; 1521 1510 } ··· 1524 1521 static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 1525 1522 { 1526 1523 unsigned int cpu = dev->id; 1527 - int ret; 1524 + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 1528 1525 1529 - /* 1530 - * Only possible if 'cpu' is getting physically removed now. A hotplug 1531 - * notifier should have already been called and we just need to remove 1532 - * link or free policy here. 1533 - */ 1534 - if (cpu_is_offline(cpu)) { 1535 - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 1536 - struct cpumask mask; 1526 + if (!policy) 1527 + return 0; 1537 1528 1538 - if (!policy) 1539 - return 0; 1529 + if (cpu_online(cpu)) { 1530 + __cpufreq_remove_dev_prepare(dev); 1531 + __cpufreq_remove_dev_finish(dev); 1532 + } 1540 1533 1541 - cpumask_copy(&mask, policy->related_cpus); 1542 - cpumask_clear_cpu(cpu, &mask); 1534 + cpumask_clear_cpu(cpu, policy->real_cpus); 1543 1535 1544 - /* 1545 - * Free policy only if all policy->related_cpus are removed 1546 - * physically. 1547 - */ 1548 - if (cpumask_intersects(&mask, cpu_present_mask)) { 1549 - remove_cpu_dev_symlink(policy, cpu); 1550 - return 0; 1551 - } 1552 - 1536 + if (cpumask_empty(policy->real_cpus)) { 1553 1537 cpufreq_policy_free(policy, true); 1554 1538 return 0; 1555 1539 } 1556 1540 1557 - ret = __cpufreq_remove_dev_prepare(dev, sif); 1541 + if (cpu != policy->kobj_cpu) { 1542 + remove_cpu_dev_symlink(policy, cpu); 1543 + } else { 1544 + /* 1545 + * The CPU owning the policy object is going away. Move it to 1546 + * another suitable CPU. 1547 + */ 1548 + unsigned int new_cpu = cpumask_first(policy->real_cpus); 1549 + struct device *new_dev = get_cpu_device(new_cpu); 1558 1550 1559 - if (!ret) 1560 - ret = __cpufreq_remove_dev_finish(dev, sif); 1551 + dev_dbg(dev, "%s: Moving policy object to CPU%u\n", __func__, new_cpu); 1561 1552 1562 - return ret; 1553 + sysfs_remove_link(&new_dev->kobj, "cpufreq"); 1554 + policy->kobj_cpu = new_cpu; 1555 + WARN_ON(kobject_move(&policy->kobj, &new_dev->kobj)); 1556 + } 1557 + 1558 + return 0; 1563 1559 } 1564 1560 1565 1561 static void handle_update(struct work_struct *work) ··· 2397 2395 break; 2398 2396 2399 2397 case CPU_DOWN_PREPARE: 2400 - __cpufreq_remove_dev_prepare(dev, NULL); 2398 + __cpufreq_remove_dev_prepare(dev); 2401 2399 break; 2402 2400 2403 2401 case CPU_POST_DEAD: 2404 - __cpufreq_remove_dev_finish(dev, NULL); 2402 + __cpufreq_remove_dev_finish(dev); 2405 2403 break; 2406 2404 2407 2405 case CPU_DOWN_FAILED:
+1
include/linux/cpufreq.h
··· 62 62 /* CPUs sharing clock, require sw coordination */ 63 63 cpumask_var_t cpus; /* Online CPUs only */ 64 64 cpumask_var_t related_cpus; /* Online + Offline CPUs */ 65 + cpumask_var_t real_cpus; /* Related and present */ 65 66 66 67 unsigned int shared_type; /* ACPI: ANY or ALL affected CPUs 67 68 should set cpufreq */