]>
Commit | Line | Data |
---|---|---|
8b80b9d4 GKH |
1 | From b7cb707c373094ce4008d4a6ac9b6b366ec52da5 Mon Sep 17 00:00:00 2001 |
2 | From: Gerald Schaefer <gerald.schaefer@de.ibm.com> | |
3 | Date: Wed, 9 Jan 2019 13:00:03 +0100 | |
4 | Subject: s390/smp: fix CPU hotplug deadlock with CPU rescan | |
5 | ||
6 | From: Gerald Schaefer <gerald.schaefer@de.ibm.com> | |
7 | ||
8 | commit b7cb707c373094ce4008d4a6ac9b6b366ec52da5 upstream. | |
9 | ||
10 | smp_rescan_cpus() is called without the device_hotplug_lock, which can lead | |
11 | to a dedlock when a new CPU is found and immediately set online by a udev | |
12 | rule. | |
13 | ||
14 | This was observed on an older kernel version, where the cpu_hotplug_begin() | |
15 | loop was still present, and it resulted in hanging chcpu and systemd-udev | |
16 | processes. This specific deadlock will not show on current kernels. However, | |
17 | there may be other possible deadlocks, and since smp_rescan_cpus() can still | |
18 | trigger a CPU hotplug operation, the device_hotplug_lock should be held. | |
19 | ||
20 | For reference, this was the deadlock with the old cpu_hotplug_begin() loop: | |
21 | ||
22 | chcpu (rescan) systemd-udevd | |
23 | ||
24 | echo 1 > /sys/../rescan | |
25 | -> smp_rescan_cpus() | |
26 | -> (*) get_online_cpus() | |
27 | (increases refcount) | |
28 | -> smp_add_present_cpu() | |
29 | (new CPU found) | |
30 | -> register_cpu() | |
31 | -> device_add() | |
32 | -> udev "add" event triggered -----------> udev rule sets CPU online | |
33 | -> echo 1 > /sys/.../online | |
34 | -> lock_device_hotplug_sysfs() | |
35 | (this is missing in rescan path) | |
36 | -> device_online() | |
37 | -> (**) device_lock(new CPU dev) | |
38 | -> cpu_up() | |
39 | -> cpu_hotplug_begin() | |
40 | (loops until refcount == 0) | |
41 | -> deadlock with (*) | |
42 | -> bus_probe_device() | |
43 | -> device_attach() | |
44 | -> device_lock(new CPU dev) | |
45 | -> deadlock with (**) | |
46 | ||
47 | Fix this by taking the device_hotplug_lock in the CPU rescan path. | |
48 | ||
49 | Cc: <stable@vger.kernel.org> | |
50 | Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> | |
51 | Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> | |
52 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
53 | ||
54 | --- | |
55 | arch/s390/kernel/smp.c | 4 ++++ | |
56 | drivers/s390/char/sclp_config.c | 2 ++ | |
57 | 2 files changed, 6 insertions(+) | |
58 | ||
59 | --- a/arch/s390/kernel/smp.c | |
60 | +++ b/arch/s390/kernel/smp.c | |
61 | @@ -1168,7 +1168,11 @@ static ssize_t __ref rescan_store(struct | |
62 | { | |
63 | int rc; | |
64 | ||
65 | + rc = lock_device_hotplug_sysfs(); | |
66 | + if (rc) | |
67 | + return rc; | |
68 | rc = smp_rescan_cpus(); | |
69 | + unlock_device_hotplug(); | |
70 | return rc ? rc : count; | |
71 | } | |
72 | static DEVICE_ATTR(rescan, 0200, NULL, rescan_store); | |
73 | --- a/drivers/s390/char/sclp_config.c | |
74 | +++ b/drivers/s390/char/sclp_config.c | |
75 | @@ -60,7 +60,9 @@ static void sclp_cpu_capability_notify(s | |
76 | ||
77 | static void __ref sclp_cpu_change_notify(struct work_struct *work) | |
78 | { | |
79 | + lock_device_hotplug(); | |
80 | smp_rescan_cpus(); | |
81 | + unlock_device_hotplug(); | |
82 | } | |
83 | ||
84 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) |