aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGautham R Shenoy <ego@in.ibm.com>2009-11-26 04:59:05 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-12-09 01:09:36 -0500
commit51badebdcf394cc5fd574a524b55b3f6085e5e9c (patch)
tree2e8173c3995f45a88826d5f453545a2c8dd86621
parentb6db63d1a7f0138f348ba7a648df35ac6365988e (diff)
powerpc/pseries: Serialize cpu hotplug operations during deactivate Vs deallocate
Currently the cpu-allocation/deallocation process comprises of two steps: - Set the indicators and to update the device tree with DLPAR node information. - Online/offline the allocated/deallocated CPU. This is achieved by writing to the sysfs tunables "probe" during allocation and "release" during deallocation. At the sametime, the userspace can independently online/offline the CPUs of the system using the sysfs tunable "online". It is quite possible that when a userspace tool offlines a CPU for the purpose of deallocation and is in the process of updating the device tree, some other userspace tool could bring the CPU back online by writing to the "online" sysfs tunable thereby causing the deallocate process to fail. The solution to this is to serialize writes to the "probe/release" sysfs tunable with the writes to the "online" sysfs tunable. This patch employs a mutex to provide this serialization, which is a no-op on all architectures except PPC_PSERIES Signed-off-by: Gautham R Shenoy <ego@in.ibm.com> Acked-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c45
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--include/linux/cpu.h13
3 files changed, 50 insertions, 10 deletions
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 642e1b2e5c42..fd2f0afeb4de 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -436,6 +436,18 @@ int dlpar_release_drc(u32 drc_index)
436 436
437#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 437#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
438 438
439static DEFINE_MUTEX(pseries_cpu_hotplug_mutex);
440
441void cpu_hotplug_driver_lock()
442{
443 mutex_lock(&pseries_cpu_hotplug_mutex);
444}
445
446void cpu_hotplug_driver_unlock()
447{
448 mutex_unlock(&pseries_cpu_hotplug_mutex);
449}
450
439static ssize_t dlpar_cpu_probe(const char *buf, size_t count) 451static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
440{ 452{
441 struct device_node *dn; 453 struct device_node *dn;
@@ -443,13 +455,18 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
443 char *cpu_name; 455 char *cpu_name;
444 int rc; 456 int rc;
445 457
458 cpu_hotplug_driver_lock();
446 rc = strict_strtoul(buf, 0, &drc_index); 459 rc = strict_strtoul(buf, 0, &drc_index);
447 if (rc) 460 if (rc) {
448 return -EINVAL; 461 rc = -EINVAL;
462 goto out;
463 }
449 464
450 dn = dlpar_configure_connector(drc_index); 465 dn = dlpar_configure_connector(drc_index);
451 if (!dn) 466 if (!dn) {
452 return -EINVAL; 467 rc = -EINVAL;
468 goto out;
469 }
453 470
454 /* configure-connector reports cpus as living in the base 471 /* configure-connector reports cpus as living in the base
455 * directory of the device tree. CPUs actually live in the 472 * directory of the device tree. CPUs actually live in the
@@ -459,7 +476,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
459 GFP_KERNEL); 476 GFP_KERNEL);
460 if (!cpu_name) { 477 if (!cpu_name) {
461 dlpar_free_cc_nodes(dn); 478 dlpar_free_cc_nodes(dn);
462 return -ENOMEM; 479 rc = -ENOMEM;
480 goto out;
463 } 481 }
464 482
465 sprintf(cpu_name, "/cpus%s", dn->full_name); 483 sprintf(cpu_name, "/cpus%s", dn->full_name);
@@ -469,7 +487,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
469 rc = dlpar_acquire_drc(drc_index); 487 rc = dlpar_acquire_drc(drc_index);
470 if (rc) { 488 if (rc) {
471 dlpar_free_cc_nodes(dn); 489 dlpar_free_cc_nodes(dn);
472 return -EINVAL; 490 rc = -EINVAL;
491 goto out;
473 } 492 }
474 493
475 rc = dlpar_attach_node(dn); 494 rc = dlpar_attach_node(dn);
@@ -479,6 +498,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
479 } 498 }
480 499
481 rc = online_node_cpus(dn); 500 rc = online_node_cpus(dn);
501out:
502 cpu_hotplug_driver_unlock();
482 503
483 return rc ? rc : count; 504 return rc ? rc : count;
484} 505}
@@ -499,26 +520,30 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
499 return -EINVAL; 520 return -EINVAL;
500 } 521 }
501 522
523 cpu_hotplug_driver_lock();
502 rc = offline_node_cpus(dn); 524 rc = offline_node_cpus(dn);
503 if (rc) { 525 if (rc) {
504 of_node_put(dn); 526 of_node_put(dn);
505 return -EINVAL; 527 rc = -EINVAL;
528 goto out;
506 } 529 }
507 530
508 rc = dlpar_release_drc(*drc_index); 531 rc = dlpar_release_drc(*drc_index);
509 if (rc) { 532 if (rc) {
510 of_node_put(dn); 533 of_node_put(dn);
511 return -EINVAL; 534 goto out;
512 } 535 }
513 536
514 rc = dlpar_detach_node(dn); 537 rc = dlpar_detach_node(dn);
515 if (rc) { 538 if (rc) {
516 dlpar_acquire_drc(*drc_index); 539 dlpar_acquire_drc(*drc_index);
517 return rc; 540 goto out;
518 } 541 }
519 542
520 of_node_put(dn); 543 of_node_put(dn);
521 return count; 544out:
545 cpu_hotplug_driver_unlock();
546 return rc ? rc : count;
522} 547}
523 548
524static int __init pseries_dlpar_init(void) 549static int __init pseries_dlpar_init(void)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 7c03af7b84a9..27fd775375b0 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -35,6 +35,7 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut
35 struct cpu *cpu = container_of(dev, struct cpu, sysdev); 35 struct cpu *cpu = container_of(dev, struct cpu, sysdev);
36 ssize_t ret; 36 ssize_t ret;
37 37
38 cpu_hotplug_driver_lock();
38 switch (buf[0]) { 39 switch (buf[0]) {
39 case '0': 40 case '0':
40 ret = cpu_down(cpu->sysdev.id); 41 ret = cpu_down(cpu->sysdev.id);
@@ -49,6 +50,7 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut
49 default: 50 default:
50 ret = -EINVAL; 51 ret = -EINVAL;
51 } 52 }
53 cpu_hotplug_driver_unlock();
52 54
53 if (ret >= 0) 55 if (ret >= 0)
54 ret = count; 56 ret = count;
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index c972f7ccb7d3..e287863ac053 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -117,6 +117,19 @@ extern void put_online_cpus(void);
117#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb) 117#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
118int cpu_down(unsigned int cpu); 118int cpu_down(unsigned int cpu);
119 119
120#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
121extern void cpu_hotplug_driver_lock(void);
122extern void cpu_hotplug_driver_unlock(void);
123#else
124static inline void cpu_hotplug_driver_lock(void)
125{
126}
127
128static inline void cpu_hotplug_driver_unlock(void)
129{
130}
131#endif
132
120#else /* CONFIG_HOTPLUG_CPU */ 133#else /* CONFIG_HOTPLUG_CPU */
121 134
122#define get_online_cpus() do { } while (0) 135#define get_online_cpus() do { } while (0)