Skip to content

Commit

Permalink
powerpc/pseries: Serialize cpu hotplug operations during deactivate V…
Browse files Browse the repository at this point in the history
…s 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>
  • Loading branch information
Gautham R Shenoy authored and Benjamin Herrenschmidt committed Dec 9, 2009
1 parent b6db63d commit 51badeb
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 10 deletions.
45 changes: 35 additions & 10 deletions arch/powerpc/platforms/pseries/dlpar.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,20 +436,37 @@ int dlpar_release_drc(u32 drc_index)

#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE

static DEFINE_MUTEX(pseries_cpu_hotplug_mutex);

void cpu_hotplug_driver_lock()
{
mutex_lock(&pseries_cpu_hotplug_mutex);
}

void cpu_hotplug_driver_unlock()
{
mutex_unlock(&pseries_cpu_hotplug_mutex);
}

static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
{
struct device_node *dn;
unsigned long drc_index;
char *cpu_name;
int rc;

cpu_hotplug_driver_lock();
rc = strict_strtoul(buf, 0, &drc_index);
if (rc)
return -EINVAL;
if (rc) {
rc = -EINVAL;
goto out;
}

dn = dlpar_configure_connector(drc_index);
if (!dn)
return -EINVAL;
if (!dn) {
rc = -EINVAL;
goto out;
}

/* configure-connector reports cpus as living in the base
* directory of the device tree. CPUs actually live in the
Expand All @@ -459,7 +476,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
GFP_KERNEL);
if (!cpu_name) {
dlpar_free_cc_nodes(dn);
return -ENOMEM;
rc = -ENOMEM;
goto out;
}

sprintf(cpu_name, "/cpus%s", dn->full_name);
Expand All @@ -469,7 +487,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
rc = dlpar_acquire_drc(drc_index);
if (rc) {
dlpar_free_cc_nodes(dn);
return -EINVAL;
rc = -EINVAL;
goto out;
}

rc = dlpar_attach_node(dn);
Expand All @@ -479,6 +498,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
}

rc = online_node_cpus(dn);
out:
cpu_hotplug_driver_unlock();

return rc ? rc : count;
}
Expand All @@ -499,26 +520,30 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
return -EINVAL;
}

cpu_hotplug_driver_lock();
rc = offline_node_cpus(dn);
if (rc) {
of_node_put(dn);
return -EINVAL;
rc = -EINVAL;
goto out;
}

rc = dlpar_release_drc(*drc_index);
if (rc) {
of_node_put(dn);
return -EINVAL;
goto out;
}

rc = dlpar_detach_node(dn);
if (rc) {
dlpar_acquire_drc(*drc_index);
return rc;
goto out;
}

of_node_put(dn);
return count;
out:
cpu_hotplug_driver_unlock();
return rc ? rc : count;
}

static int __init pseries_dlpar_init(void)
Expand Down
2 changes: 2 additions & 0 deletions drivers/base/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut
struct cpu *cpu = container_of(dev, struct cpu, sysdev);
ssize_t ret;

cpu_hotplug_driver_lock();
switch (buf[0]) {
case '0':
ret = cpu_down(cpu->sysdev.id);
Expand All @@ -49,6 +50,7 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut
default:
ret = -EINVAL;
}
cpu_hotplug_driver_unlock();

if (ret >= 0)
ret = count;
Expand Down
13 changes: 13 additions & 0 deletions include/linux/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ extern void put_online_cpus(void);
#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
int cpu_down(unsigned int cpu);

#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
extern void cpu_hotplug_driver_lock(void);
extern void cpu_hotplug_driver_unlock(void);
#else
static inline void cpu_hotplug_driver_lock(void)
{
}

static inline void cpu_hotplug_driver_unlock(void)
{
}
#endif

#else /* CONFIG_HOTPLUG_CPU */

#define get_online_cpus() do { } while (0)
Expand Down

0 comments on commit 51badeb

Please sign in to comment.