@@ -741,6 +741,20 @@ Add device to remote proc.
ETEXI
{
+ .name = "rdevice_del",
+ .args_type = "rdev_id:s,id:s",
+ .params = "rdev_id id",
+ .help = "remove device from remote proc",
+ .cmd = hmp_rdevice_del,
+ },
+
+STEXI
+@item rdevice_del @var{rdev_id} @var{id}
+@findex rdevice_del
+Remove device from remote proc.
+ETEXI
+
+ {
.name = "remote_proc_list",
.args_type = "",
.params = "",
@@ -151,5 +151,6 @@ void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
void hmp_info_sev(Monitor *mon, const QDict *qdict);
void hmp_remote_proc_list(Monitor *mon, const QDict *qdict);
void hmp_rdevice_add(Monitor *mon, const QDict *qdict);
+void hmp_rdevice_del(Monitor *mon, const QDict *qdict);
#endif
@@ -158,6 +158,8 @@ static void rdevice_add_del(QDict *qdict, proc_cmd_t cmd, Error **errp)
if (cmd == DEVICE_ADD) {
(void)g_hash_table_insert(pcms->remote_devs, (gpointer)g_strdup(id),
(gpointer)pdev);
+ } else {
+ (void)g_hash_table_remove(pcms->remote_devs, (gpointer)id);
}
}
@@ -179,3 +181,23 @@ void hmp_rdevice_add(Monitor *mon, const QDict *qdict)
error_free(err);
}
}
+
+void qmp_rdevice_del(QDict *qdict, QObject **ret_data, Error **errp)
+{
+ rdevice_add_del(qdict, DEVICE_DEL, errp);
+}
+
+void hmp_rdevice_del(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+
+ /* TODO: Is it OK to modify the QDict argument from HMP? */
+ rdevice_add_del((QDict *)qdict, DEVICE_DEL, &err);
+
+ if (err) {
+ monitor_printf(mon, "rdevice_del error: %s\n",
+ error_get_pretty(err));
+ error_free(err);
+ }
+}
+
@@ -358,6 +358,7 @@ BusState *qdev_get_parent_bus(DeviceState *dev);
/*** BUS API. ***/
DeviceState *qdev_find_recursive(BusState *bus, const char *id);
+DeviceState *find_device_state(const char *id, Error **errp);
/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */
typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
@@ -61,6 +61,7 @@ typedef struct ProxyLinkState ProxyLinkState;
* SET_IRQFD Sets the IRQFD to be used to raise interrupts directly
* from remote device
* DEVICE_ADD QMP/HMP command to hotplug device
+ * DEVICE_DEL QMP/HMP command to hot-unplug device
*
*/
typedef enum {
@@ -72,6 +73,7 @@ typedef enum {
BAR_READ,
SET_IRQFD,
DEVICE_ADD,
+ DEVICE_DEL,
MAX,
} proc_cmd_t;
@@ -12,6 +12,7 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
#ifdef CONFIG_MPQEMU
void qmp_rdevice_add(QDict *qdict, QObject **ret_data, Error **errp);
+void qmp_rdevice_del(QDict *qdict, QObject **ret_data, Error **errp);
#endif
int qdev_device_help(QemuOpts *opts);
@@ -1158,6 +1158,8 @@ static void monitor_init_qmp_commands(void)
#ifdef CONFIG_MPQEMU
qmp_register_command(&qmp_commands, "rdevice_add", qmp_rdevice_add,
QCO_NO_OPTIONS);
+ qmp_register_command(&qmp_commands, "rdevice_del", qmp_rdevice_del,
+ QCO_NO_OPTIONS);
#endif
QTAILQ_INIT(&qmp_cap_negotiation_commands);
@@ -1717,6 +1717,33 @@
{ 'command': 'device_del', 'data': {'id': 'str'} }
##
+# @rdevice_del:
+#
+# Remove a device from a guest
+#
+# @rdev_id: ID of the remote device root
+#
+# @id: the device's ID
+#
+# Returns: Nothing on success
+# If @id is not a valid device, DeviceNotFound
+#
+# Notes: When this command completes, the device may not be removed from the
+# guest. Hot removal is an operation that requires guest cooperation.
+# This command merely requests that the guest begin the hot removal
+# process. Completion of the device removal process is signaled with a
+# DEVICE_DELETED event. Guest reset will automatically complete removal
+# for all devices.
+#
+# Since: 3.0
+#
+##
+{ 'command': 'rdevice_del',
+ 'data': {'rdev_id': 'str', 'id': 'str'},
+ 'if': 'defined(CONFIG_MPQEMU)',
+ 'gen': false }
+
+##
# @DEVICE_DELETED:
#
# Emitted whenever the device removal completion is acknowledged by the guest.
@@ -828,7 +828,7 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
object_unref(OBJECT(dev));
}
-static DeviceState *find_device_state(const char *id, Error **errp)
+DeviceState *find_device_state(const char *id, Error **errp)
{
Object *obj;
@@ -53,6 +53,7 @@
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "monitor/qdev.h"
+#include "qapi/qmp/qdict.h"
static ProxyLinkState *proxy_link;
PCIDevice *remote_pci_dev;
@@ -181,6 +182,47 @@ fail:
PUT_REMOTE_WAIT(wait);
}
+static void process_device_del_msg(ProcMsg *msg)
+{
+ Error *local_err = NULL;
+ DeviceState *dev = NULL;
+ const char *json = (const char *)msg->data2;
+ int wait = msg->fds[0];
+ QObject *qobj = NULL;
+ QDict *qdict = NULL;
+ const char *id;
+
+ qobj = qobject_from_json(json, &local_err);
+ if (local_err) {
+ goto fail;
+ }
+
+ qdict = qobject_to(QDict, qobj);
+ assert(qdict);
+
+ id = qdict_get_try_str(qdict, "id");
+ assert(id);
+
+ dev = find_device_state(id, &local_err);
+ if (local_err) {
+ goto fail;
+ }
+
+ if (dev) {
+ qdev_unplug(dev, &local_err);
+ }
+
+fail:
+ if (local_err) {
+ error_report_err(local_err);
+ /* TODO: communicate the exact error message to proxy */
+ }
+
+ notify_proxy(wait, 1);
+
+ PUT_REMOTE_WAIT(wait);
+}
+
static void process_msg(GIOCondition cond)
{
ProcMsg *msg = NULL;
@@ -235,6 +277,9 @@ static void process_msg(GIOCondition cond)
case DEVICE_ADD:
process_device_add_msg(msg);
break;
+ case DEVICE_DEL:
+ process_device_del_msg(msg);
+ break;
default:
error_setg(&err, "Unknown command");
goto finalize_loop;