New patch | |||
---|---|---|---|
1 | Akihiko's v4 patch was doing too many things at once to | ||
2 | my taste, so I split it to follow dumbly each steps. | ||
3 | https://lore.kernel.org/qemu-devel/20250104-bus-v4-1-244cf1c6e2aa@daynix.com/ | ||
1 | 4 | ||
5 | Akihiko Odaki (6): | ||
6 | hw/qdev: Pass bus argument to qdev_hotplug_allowed() | ||
7 | hw/qdev: Factor qdev_hotunplug_allowed() out | ||
8 | hw/qdev: Introduce qdev_hotplug_unplug_allowed_common() | ||
9 | hw/qdev: Check DevClass::hotpluggable in hotplug_unplug_allowed_common | ||
10 | hw/qdev: Check qbus_is_hotpluggable in hotplug_unplug_allowed_common | ||
11 | hw/qdev: Check machine_hotplug_handler in | ||
12 | hotplug_unplug_allowed_common | ||
13 | |||
14 | include/hw/qdev-core.h | 3 ++- | ||
15 | hw/core/qdev-hotplug.c | 42 +++++++++++++++++++++++++++++++++++++++++- | ||
16 | system/qdev-monitor.c | 37 +++++-------------------------------- | ||
17 | 3 files changed, 48 insertions(+), 34 deletions(-) | ||
18 | |||
19 | -- | ||
20 | 2.47.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
1 | 2 | ||
3 | In preparation of checking the parent bus is hot(un)pluggable | ||
4 | in a few commits, pass a 'bus' argument to qdev_hotplug_allowed(). | ||
5 | |||
6 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | --- | ||
9 | include/hw/qdev-core.h | 2 +- | ||
10 | hw/core/qdev-hotplug.c | 2 +- | ||
11 | system/qdev-monitor.c | 2 +- | ||
12 | 3 files changed, 3 insertions(+), 3 deletions(-) | ||
13 | |||
14 | diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/hw/qdev-core.h | ||
17 | +++ b/include/hw/qdev-core.h | ||
18 | @@ -XXX,XX +XXX,XX @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, | ||
19 | int required_for_version); | ||
20 | HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev); | ||
21 | HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); | ||
22 | -bool qdev_hotplug_allowed(DeviceState *dev, Error **errp); | ||
23 | +bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp); | ||
24 | |||
25 | /** | ||
26 | * qdev_get_hotplug_handler() - Get handler responsible for device wiring | ||
27 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/hw/core/qdev-hotplug.c | ||
30 | +++ b/hw/core/qdev-hotplug.c | ||
31 | @@ -XXX,XX +XXX,XX @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) | ||
32 | return NULL; | ||
33 | } | ||
34 | |||
35 | -bool qdev_hotplug_allowed(DeviceState *dev, Error **errp) | ||
36 | +bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp) | ||
37 | { | ||
38 | MachineState *machine; | ||
39 | MachineClass *mc; | ||
40 | diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/system/qdev-monitor.c | ||
43 | +++ b/system/qdev-monitor.c | ||
44 | @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, | ||
45 | |||
46 | /* Check whether the hotplug is allowed by the machine */ | ||
47 | if (phase_check(PHASE_MACHINE_READY)) { | ||
48 | - if (!qdev_hotplug_allowed(dev, errp)) { | ||
49 | + if (!qdev_hotplug_allowed(dev, bus, errp)) { | ||
50 | goto err_del_dev; | ||
51 | } | ||
52 | |||
53 | -- | ||
54 | 2.47.1 | ||
55 | |||
56 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
1 | 2 | ||
3 | Factor qdev_hotunplug_allowed() out of qdev_unplug(). | ||
4 | Start checking the device is not blocked. | ||
5 | |||
6 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | --- | ||
9 | include/hw/qdev-core.h | 1 + | ||
10 | hw/core/qdev-hotplug.c | 5 +++++ | ||
11 | system/qdev-monitor.c | 2 +- | ||
12 | 3 files changed, 7 insertions(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/hw/qdev-core.h | ||
17 | +++ b/include/hw/qdev-core.h | ||
18 | @@ -XXX,XX +XXX,XX @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, | ||
19 | HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev); | ||
20 | HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); | ||
21 | bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp); | ||
22 | +bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp); | ||
23 | |||
24 | /** | ||
25 | * qdev_get_hotplug_handler() - Get handler responsible for device wiring | ||
26 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/hw/core/qdev-hotplug.c | ||
29 | +++ b/hw/core/qdev-hotplug.c | ||
30 | @@ -XXX,XX +XXX,XX @@ bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp) | ||
31 | return true; | ||
32 | } | ||
33 | |||
34 | +bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp) | ||
35 | +{ | ||
36 | + return !qdev_unplug_blocked(dev, errp); | ||
37 | +} | ||
38 | + | ||
39 | HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev) | ||
40 | { | ||
41 | if (dev->parent_bus) { | ||
42 | diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c | ||
43 | index XXXXXXX..XXXXXXX 100644 | ||
44 | --- a/system/qdev-monitor.c | ||
45 | +++ b/system/qdev-monitor.c | ||
46 | @@ -XXX,XX +XXX,XX @@ void qdev_unplug(DeviceState *dev, Error **errp) | ||
47 | HotplugHandlerClass *hdc; | ||
48 | Error *local_err = NULL; | ||
49 | |||
50 | - if (qdev_unplug_blocked(dev, errp)) { | ||
51 | + if (!qdev_hotunplug_allowed(dev, errp)) { | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | -- | ||
56 | 2.47.1 | ||
57 | |||
58 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
1 | 2 | ||
3 | Introduce qdev_hotplug_unplug_allowed_common() to hold | ||
4 | common code between checking hot-plug/unplug is allowed. | ||
5 | |||
6 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | --- | ||
9 | hw/core/qdev-hotplug.c | 13 ++++++++++++- | ||
10 | 1 file changed, 12 insertions(+), 1 deletion(-) | ||
11 | |||
12 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/hw/core/qdev-hotplug.c | ||
15 | +++ b/hw/core/qdev-hotplug.c | ||
16 | @@ -XXX,XX +XXX,XX @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) | ||
17 | return NULL; | ||
18 | } | ||
19 | |||
20 | +static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus, | ||
21 | + Error **errp) | ||
22 | +{ | ||
23 | + return true; | ||
24 | +} | ||
25 | + | ||
26 | bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp) | ||
27 | { | ||
28 | MachineState *machine; | ||
29 | MachineClass *mc; | ||
30 | Object *m_obj = qdev_get_machine(); | ||
31 | |||
32 | + if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) { | ||
33 | + return false; | ||
34 | + } | ||
35 | + | ||
36 | if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { | ||
37 | machine = MACHINE(m_obj); | ||
38 | mc = MACHINE_GET_CLASS(machine); | ||
39 | @@ -XXX,XX +XXX,XX @@ bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp) | ||
40 | |||
41 | bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp) | ||
42 | { | ||
43 | - return !qdev_unplug_blocked(dev, errp); | ||
44 | + return !qdev_unplug_blocked(dev, errp) && | ||
45 | + qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp); | ||
46 | } | ||
47 | |||
48 | HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev) | ||
49 | -- | ||
50 | 2.47.1 | ||
51 | |||
52 | diff view generated by jsdifflib |
1 | Commit 03fcbd9dc508 ("qdev: Check for the availability of a hotplug | 1 | From: Akihiko Odaki <akihiko.odaki@daynix.com> |
---|---|---|---|
2 | controller before adding a device") says: | ||
3 | > The qdev_unplug() function contains a g_assert(hotplug_ctrl) | ||
4 | > statement, so QEMU crashes when the user tries to device_add + | ||
5 | > device_del a device that does not have a corresponding hotplug | ||
6 | > controller. | ||
7 | 2 | ||
8 | > The code in qdev_device_add() already checks whether the bus has a | 3 | Check the same code once in the common helper. |
9 | > proper hotplug controller, but for devices that do not have a | ||
10 | > corresponding bus, here is no appropriate check available yet. In that | ||
11 | > case we should check whether the machine itself provides a suitable | ||
12 | > hotplug controller and refuse to plug the device if none is available. | ||
13 | 4 | ||
14 | However, it forgot to add the corresponding check to qdev_unplug(). | 5 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
6 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
7 | --- | ||
8 | hw/core/qdev-hotplug.c | 9 +++++++++ | ||
9 | system/qdev-monitor.c | 10 +--------- | ||
10 | 2 files changed, 10 insertions(+), 9 deletions(-) | ||
15 | 11 | ||
16 | Most checks are comon between the hot-plug and hot-unplug scenarios so | ||
17 | extract them and share the implementation, saving some code and fixing | ||
18 | the aforementioned bug. | ||
19 | |||
20 | Fixes: 7716b8ca74 ("qdev: HotplugHandler: Add support for unplugging BUS-less devices") | ||
21 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
22 | --- | ||
23 | Changes in v4: | ||
24 | - Rebased. | ||
25 | - Link to v3: https://lore.kernel.org/r/20240218-bus-v3-1-877725ce6d15@daynix.com | ||
26 | |||
27 | Changes in v3: | ||
28 | - Extracted checks common for hot-plug and hot-unplug into a function. | ||
29 | - Link to v2: https://lore.kernel.org/r/20231210-bus-v2-1-34ebf5726fa0@daynix.com | ||
30 | |||
31 | Changes in v2: | ||
32 | - Fixed indention. | ||
33 | - Link to v1: https://lore.kernel.org/r/20231202-bus-v1-1-f7540e3a8d62@daynix.com | ||
34 | --- | ||
35 | include/hw/qdev-core.h | 3 ++- | ||
36 | hw/core/qdev-hotplug.c | 42 +++++++++++++++++++++++++++++++++++++++++- | ||
37 | system/qdev-monitor.c | 37 +++++-------------------------------- | ||
38 | 3 files changed, 48 insertions(+), 34 deletions(-) | ||
39 | |||
40 | diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/include/hw/qdev-core.h | ||
43 | +++ b/include/hw/qdev-core.h | ||
44 | @@ -XXX,XX +XXX,XX @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, | ||
45 | int required_for_version); | ||
46 | HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev); | ||
47 | HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); | ||
48 | -bool qdev_hotplug_allowed(DeviceState *dev, Error **errp); | ||
49 | +bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp); | ||
50 | +bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp); | ||
51 | |||
52 | /** | ||
53 | * qdev_get_hotplug_handler() - Get handler responsible for device wiring | ||
54 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c | 12 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c |
55 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
56 | --- a/hw/core/qdev-hotplug.c | 14 | --- a/hw/core/qdev-hotplug.c |
57 | +++ b/hw/core/qdev-hotplug.c | 15 | +++ b/hw/core/qdev-hotplug.c |
58 | @@ -XXX,XX +XXX,XX @@ | 16 | @@ -XXX,XX +XXX,XX @@ |
... | ... | ||
62 | +#include "qapi/error.h" | 20 | +#include "qapi/error.h" |
63 | 21 | ||
64 | HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) | 22 | HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) |
65 | { | 23 | { |
66 | @@ -XXX,XX +XXX,XX @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) | 24 | @@ -XXX,XX +XXX,XX @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) |
67 | return NULL; | 25 | static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus, |
68 | } | 26 | Error **errp) |
69 | 27 | { | |
70 | -bool qdev_hotplug_allowed(DeviceState *dev, Error **errp) | ||
71 | +static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus, | ||
72 | + Error **errp) | ||
73 | +{ | ||
74 | + DeviceClass *dc = DEVICE_GET_CLASS(dev); | 28 | + DeviceClass *dc = DEVICE_GET_CLASS(dev); |
75 | + | 29 | + |
76 | + if (!dc->hotpluggable) { | 30 | + if (!dc->hotpluggable) { |
77 | + error_setg(errp, "Device '%s' does not support hotplugging", | 31 | + error_setg(errp, "Device '%s' does not support hotplugging", |
78 | + object_get_typename(OBJECT(dev))); | 32 | + object_get_typename(OBJECT(dev))); |
79 | + return false; | 33 | + return false; |
80 | + } | 34 | + } |
81 | + | 35 | + |
82 | + if (bus) { | ||
83 | + if (!qbus_is_hotpluggable(bus)) { | ||
84 | + error_setg(errp, "Bus '%s' does not support hotplugging", | ||
85 | + bus->name); | ||
86 | + return false; | ||
87 | + } | ||
88 | + } else { | ||
89 | + if (!qdev_get_machine_hotplug_handler(dev)) { | ||
90 | + /* No bus, no machine hotplug handler --> device is not hotpluggable */ | ||
91 | + error_setg(errp, "Device '%s' can not be hotplugged on this machine", | ||
92 | + object_get_typename(OBJECT(dev))); | ||
93 | + return false; | ||
94 | + } | ||
95 | + } | ||
96 | + | ||
97 | + return true; | ||
98 | +} | ||
99 | + | ||
100 | +bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp) | ||
101 | { | ||
102 | MachineState *machine; | ||
103 | MachineClass *mc; | ||
104 | Object *m_obj = qdev_get_machine(); | ||
105 | |||
106 | + if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) { | ||
107 | + return false; | ||
108 | + } | ||
109 | + | ||
110 | if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { | ||
111 | machine = MACHINE(m_obj); | ||
112 | mc = MACHINE_GET_CLASS(machine); | ||
113 | @@ -XXX,XX +XXX,XX @@ bool qdev_hotplug_allowed(DeviceState *dev, Error **errp) | ||
114 | return true; | 36 | return true; |
115 | } | 37 | } |
116 | 38 | ||
117 | +bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp) | ||
118 | +{ | ||
119 | + return !qdev_unplug_blocked(dev, errp) && | ||
120 | + qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp); | ||
121 | +} | ||
122 | + | ||
123 | HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev) | ||
124 | { | ||
125 | if (dev->parent_bus) { | ||
126 | diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c | 39 | diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c |
127 | index XXXXXXX..XXXXXXX 100644 | 40 | index XXXXXXX..XXXXXXX 100644 |
128 | --- a/system/qdev-monitor.c | 41 | --- a/system/qdev-monitor.c |
129 | +++ b/system/qdev-monitor.c | 42 | +++ b/system/qdev-monitor.c |
130 | @@ -XXX,XX +XXX,XX @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp) | 43 | @@ -XXX,XX +XXX,XX @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp) |
... | ... | ||
135 | - (phase_check(PHASE_MACHINE_READY) && !dc->hotpluggable)) { | 48 | - (phase_check(PHASE_MACHINE_READY) && !dc->hotpluggable)) { |
136 | + if (!dc->user_creatable) { | 49 | + if (!dc->user_creatable) { |
137 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", | 50 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", |
138 | "a pluggable device type"); | 51 | "a pluggable device type"); |
139 | return NULL; | 52 | return NULL; |
140 | @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | - if (phase_check(PHASE_MACHINE_READY) && bus && !qbus_is_hotpluggable(bus)) { | ||
145 | - error_setg(errp, "Bus '%s' does not support hotplugging", bus->name); | ||
146 | - return NULL; | ||
147 | - } | ||
148 | - | ||
149 | if (migration_is_running()) { | ||
150 | error_setg(errp, "device_add not allowed while migrating"); | ||
151 | return NULL; | ||
152 | @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, | ||
153 | dev = qdev_new(driver); | ||
154 | |||
155 | /* Check whether the hotplug is allowed by the machine */ | ||
156 | - if (phase_check(PHASE_MACHINE_READY)) { | ||
157 | - if (!qdev_hotplug_allowed(dev, errp)) { | ||
158 | - goto err_del_dev; | ||
159 | - } | ||
160 | - | ||
161 | - if (!bus && !qdev_get_machine_hotplug_handler(dev)) { | ||
162 | - /* No bus, no machine hotplug handler --> device is not hotpluggable */ | ||
163 | - error_setg(errp, "Device '%s' can not be hotplugged on this machine", | ||
164 | - driver); | ||
165 | - goto err_del_dev; | ||
166 | - } | ||
167 | + if (phase_check(PHASE_MACHINE_READY) && | ||
168 | + !qdev_hotplug_allowed(dev, bus, errp)) { | ||
169 | + goto err_del_dev; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | @@ -XXX,XX +XXX,XX @@ static DeviceState *find_device_state(const char *id, bool use_generic_error, | 53 | @@ -XXX,XX +XXX,XX @@ static DeviceState *find_device_state(const char *id, bool use_generic_error, |
174 | 54 | ||
175 | void qdev_unplug(DeviceState *dev, Error **errp) | 55 | void qdev_unplug(DeviceState *dev, Error **errp) |
176 | { | 56 | { |
177 | - DeviceClass *dc = DEVICE_GET_CLASS(dev); | 57 | - DeviceClass *dc = DEVICE_GET_CLASS(dev); |
178 | HotplugHandler *hotplug_ctrl; | 58 | HotplugHandler *hotplug_ctrl; |
179 | HotplugHandlerClass *hdc; | 59 | HotplugHandlerClass *hdc; |
180 | Error *local_err = NULL; | 60 | Error *local_err = NULL; |
181 | 61 | @@ -XXX,XX +XXX,XX @@ void qdev_unplug(DeviceState *dev, Error **errp) | |
182 | - if (qdev_unplug_blocked(dev, errp)) { | 62 | return; |
63 | } | ||
64 | |||
65 | - if (!dc->hotpluggable) { | ||
66 | - error_setg(errp, "Device '%s' does not support hotplugging", | ||
67 | - object_get_typename(OBJECT(dev))); | ||
183 | - return; | 68 | - return; |
184 | - } | 69 | - } |
185 | - | 70 | - |
186 | - if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) { | 71 | if (migration_is_running() && !dev->allow_unplug_during_migration) { |
187 | - error_setg(errp, "Bus '%s' does not support hotplugging", | 72 | error_setg(errp, "device_del not allowed while migrating"); |
188 | - dev->parent_bus->name); | ||
189 | - return; | ||
190 | - } | ||
191 | - | ||
192 | - if (!dc->hotpluggable) { | ||
193 | - error_setg(errp, "Device '%s' does not support hotplugging", | ||
194 | - object_get_typename(OBJECT(dev))); | ||
195 | + if (!qdev_hotunplug_allowed(dev, errp)) { | ||
196 | return; | 73 | return; |
197 | } | 74 | -- |
198 | 75 | 2.47.1 | |
199 | 76 | ||
200 | --- | ||
201 | base-commit: 38d0939b86e2eef6f6a622c6f1f7befda0146595 | ||
202 | change-id: 20231202-bus-75a454c5d959 | ||
203 | 77 | ||
204 | Best regards, | ||
205 | -- | ||
206 | Akihiko Odaki <akihiko.odaki@daynix.com> | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
1 | 2 | ||
3 | Check the same code once in the common helper. | ||
4 | |||
5 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
6 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
7 | --- | ||
8 | hw/core/qdev-hotplug.c | 8 ++++++++ | ||
9 | system/qdev-monitor.c | 11 ----------- | ||
10 | 2 files changed, 8 insertions(+), 11 deletions(-) | ||
11 | |||
12 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/hw/core/qdev-hotplug.c | ||
15 | +++ b/hw/core/qdev-hotplug.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus, | ||
17 | return false; | ||
18 | } | ||
19 | |||
20 | + if (bus) { | ||
21 | + if (!qbus_is_hotpluggable(bus)) { | ||
22 | + error_setg(errp, "Bus '%s' does not support hotplugging", | ||
23 | + bus->name); | ||
24 | + return false; | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | return true; | ||
29 | } | ||
30 | |||
31 | diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/system/qdev-monitor.c | ||
34 | +++ b/system/qdev-monitor.c | ||
35 | @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, | ||
36 | return NULL; | ||
37 | } | ||
38 | |||
39 | - if (phase_check(PHASE_MACHINE_READY) && bus && !qbus_is_hotpluggable(bus)) { | ||
40 | - error_setg(errp, "Bus '%s' does not support hotplugging", bus->name); | ||
41 | - return NULL; | ||
42 | - } | ||
43 | - | ||
44 | if (migration_is_running()) { | ||
45 | error_setg(errp, "device_add not allowed while migrating"); | ||
46 | return NULL; | ||
47 | @@ -XXX,XX +XXX,XX @@ void qdev_unplug(DeviceState *dev, Error **errp) | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | - if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) { | ||
52 | - error_setg(errp, "Bus '%s' does not support hotplugging", | ||
53 | - dev->parent_bus->name); | ||
54 | - return; | ||
55 | - } | ||
56 | - | ||
57 | if (migration_is_running() && !dev->allow_unplug_during_migration) { | ||
58 | error_setg(errp, "device_del not allowed while migrating"); | ||
59 | return; | ||
60 | -- | ||
61 | 2.47.1 | ||
62 | |||
63 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
1 | 2 | ||
3 | Commit 03fcbd9dc508 ("qdev: Check for the availability of a hotplug | ||
4 | controller before adding a device") says: | ||
5 | |||
6 | > The qdev_unplug() function contains a g_assert(hotplug_ctrl) | ||
7 | > statement, so QEMU crashes when the user tries to device_add + | ||
8 | > device_del a device that does not have a corresponding hotplug | ||
9 | > controller. | ||
10 | |||
11 | > The code in qdev_device_add() already checks whether the bus has a | ||
12 | > proper hotplug controller, but for devices that do not have a | ||
13 | > corresponding bus, here is no appropriate check available yet. In that | ||
14 | > case we should check whether the machine itself provides a suitable | ||
15 | > hotplug controller and refuse to plug the device if none is available. | ||
16 | |||
17 | However, it forgot to add the corresponding check to qdev_unplug(). | ||
18 | |||
19 | Check the machine hotplug handler once in the common | ||
20 | qdev_hotplug_unplug_allowed_common() helper so both hotplug | ||
21 | and hot-unplug path are covered. | ||
22 | |||
23 | Fixes: 7716b8ca74 ("qdev: HotplugHandler: Add support for unplugging BUS-less devices") | ||
24 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
25 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
26 | --- | ||
27 | hw/core/qdev-hotplug.c | 7 +++++++ | ||
28 | system/qdev-monitor.c | 14 +++----------- | ||
29 | 2 files changed, 10 insertions(+), 11 deletions(-) | ||
30 | |||
31 | diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/hw/core/qdev-hotplug.c | ||
34 | +++ b/hw/core/qdev-hotplug.c | ||
35 | @@ -XXX,XX +XXX,XX @@ static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus, | ||
36 | bus->name); | ||
37 | return false; | ||
38 | } | ||
39 | + } else { | ||
40 | + if (!qdev_get_machine_hotplug_handler(dev)) { | ||
41 | + /* No bus, no machine hotplug handler --> device is not hotpluggable */ | ||
42 | + error_setg(errp, "Device '%s' can not be hotplugged on this machine", | ||
43 | + object_get_typename(OBJECT(dev))); | ||
44 | + return false; | ||
45 | + } | ||
46 | } | ||
47 | |||
48 | return true; | ||
49 | diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/system/qdev-monitor.c | ||
52 | +++ b/system/qdev-monitor.c | ||
53 | @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, | ||
54 | dev = qdev_new(driver); | ||
55 | |||
56 | /* Check whether the hotplug is allowed by the machine */ | ||
57 | - if (phase_check(PHASE_MACHINE_READY)) { | ||
58 | - if (!qdev_hotplug_allowed(dev, bus, errp)) { | ||
59 | - goto err_del_dev; | ||
60 | - } | ||
61 | - | ||
62 | - if (!bus && !qdev_get_machine_hotplug_handler(dev)) { | ||
63 | - /* No bus, no machine hotplug handler --> device is not hotpluggable */ | ||
64 | - error_setg(errp, "Device '%s' can not be hotplugged on this machine", | ||
65 | - driver); | ||
66 | - goto err_del_dev; | ||
67 | - } | ||
68 | + if (phase_check(PHASE_MACHINE_READY) && | ||
69 | + !qdev_hotplug_allowed(dev, bus, errp)) { | ||
70 | + goto err_del_dev; | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | -- | ||
75 | 2.47.1 | ||
76 | |||
77 | diff view generated by jsdifflib |