diff options
author | Nathan Fontenot <nfont@linux.vnet.ibm.com> | 2015-10-23 12:45:57 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-12-17 22:41:01 +1100 |
commit | 1f859adb9253c201079962582253236e9b2cc3ce (patch) | |
tree | 530f2fdf162205d654e5f7df1c3726fa9586b41d /arch | |
parent | 4450022b4952ce67d2f3006b4c38e12a0f38cd77 (diff) | |
download | linux-1f859adb9253c201079962582253236e9b2cc3ce.tar.bz2 |
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 <nfont@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/pseries/dlpar.c | 43 |
1 files 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) { |