From 1f859adb9253c201079962582253236e9b2cc3ce Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 23 Oct 2015 12:45:57 -0500 Subject: [PATCH] powerpc/pseries: Verify CPU doesn't exist before adding When DLPAR adding a CPU we should verify that the CPU does not already exist. Failure to do so can generate a kernel oops; [ 9.465585] kernel BUG at arch/powerpc/platforms/pseries/dlpar.c:382! [ 9.465796] Oops: Exception in kernel mode, sig: 5 [#1] This oops can be generated by causing a probe to be performed on a cpu by writing to the sysfs cpu probe file (/sys/devices/system/cpu/probe). This patch adds a check for the existence of cpu prior to probing the cpu so userspace doing the wrong thing won't trigger a BUG_ON(). Signed-off-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/dlpar.c | 43 +++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index f244dcb4f2cf..fe6320db9255 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -381,6 +381,32 @@ out: } +static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index) +{ + struct device_node *child = NULL; + u32 my_drc_index; + bool found; + int rc; + + /* Assume cpu doesn't exist */ + found = false; + + for_each_child_of_node(parent, child) { + rc = of_property_read_u32(child, "ibm,my-drc-index", + &my_drc_index); + if (rc) + continue; + + if (my_drc_index == drc_index) { + of_node_put(child); + found = true; + break; + } + } + + return found; +} + static ssize_t dlpar_cpu_probe(const char *buf, size_t count) { struct device_node *dn, *parent; @@ -391,14 +417,23 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count) if (rc) return -EINVAL; - rc = dlpar_acquire_drc(drc_index); - if (rc) - return -EINVAL; - parent = of_find_node_by_path("/cpus"); if (!parent) return -ENODEV; + if (dlpar_cpu_exists(parent, drc_index)) { + of_node_put(parent); + printk(KERN_WARNING "CPU with drc index %x already exists\n", + drc_index); + return -EINVAL; + } + + rc = dlpar_acquire_drc(drc_index); + if (rc) { + of_node_put(parent); + return -EINVAL; + } + dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent); of_node_put(parent); if (!dn) { -- 2.30.2