3e5111
From 2d1d83a1d3eeb7cf98972c461842f333f900c1e2 Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <2d1d83a1d3eeb7cf98972c461842f333f900c1e2@dist-git>
6ae9ed
From: Jiri Denemark <jdenemar@redhat.com>
6ae9ed
Date: Tue, 5 Apr 2016 09:14:09 +0200
9119d9
Subject: [PATCH] RHEL: Support virtio disk hotplug in JSON mode
c401cc
c401cc
RHEL only, no upstream
c401cc
c401cc
For bug
c401cc
  https://bugzilla.redhat.com/show_bug.cgi?id=1026966
c401cc
  https://bugzilla.redhat.com/show_bug.cgi?id=573946
c401cc
c401cc
The existing drive_add command can hotplug SCSI and VirtIO
c401cc
disks, but this isn't ported to JSON mode. RHEL6 introduces
c401cc
a custom __com.redhat_drive_add that only supports VirtIO
c401cc
disks. Switch the VirtIO hotplug to this command, but leave
c401cc
the SCSI hotplug using old command so SCSI gets an explicit
c401cc
error about being unsupported.
c401cc
c401cc
* src/libvirt_private.syms: Export virJSONValueObjectRemoveKey
c401cc
* src/util/json.c, src/util/json.h: Add virJSONValueObjectRemoveKey
c401cc
  to allow a key to be deleted from an object
c401cc
* src/qemu/qemu_monitor_json.c: Try __com.redhat_drive_add first and use
c401cc
  drive_add only if the redhat command is not known to qemu.
c401cc
c401cc
Also includes the following fix:
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=696596
c401cc
c401cc
Upstream added drive_del as a way to ensure that disks are fully
c401cc
removed before returning control to libvirt.  But RHEL backported
c401cc
it as __com.redhat_drive_del, prior to upstream adoption of a
c401cc
QMP counterpart.  Because we weren't trying the RHEL-specific
c401cc
spelling, we were falling back to the unsafe approach of just
c401cc
removing the device and hoping for the best, which was racy and
c401cc
could occasionally result in a rapid hot-plug cycle trying to
c401cc
plug in a new disk that collides with the old disk not yet gone.
c401cc
c401cc
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONDriveDel): Try
c401cc
rhel-specific drive_del monitor command first.
c401cc
c401cc
(cherry picked from commit d1c200dfead14a590a4ddebe20a20ffe441d2b24 in
c401cc
rhel-6.5 branch)
c401cc
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
c401cc
Conflicts:
c401cc
	src/libvirt_private.syms - the change is already upstream
c401cc
        src/util/virjson.[ch] - the change is already upstream
c401cc
	src/qemu/qemu_monitor_json.c - context; upstream doesn't try to
c401cc
	    call nonexistent drive_{add,del} QMP commands any more
c401cc
---
6ae9ed
 src/qemu/qemu_monitor.c      |  12 +++--
6ae9ed
 src/qemu/qemu_monitor_json.c | 106 +++++++++++++++++++++++++++++++++++++++++++
6ae9ed
 src/qemu/qemu_monitor_json.h |   6 +++
3e5111
 tests/qemuhotplugtest.c      |  92 ++++++++++++++++++++++++++++++++++++-
3e5111
 4 files changed, 210 insertions(+), 6 deletions(-)
c401cc
6ae9ed
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
3e5111
index 8bc00bc1e..488d761fb 100644
6ae9ed
--- a/src/qemu/qemu_monitor.c
6ae9ed
+++ b/src/qemu/qemu_monitor.c
3e5111
@@ -3073,8 +3073,10 @@ qemuMonitorDriveDel(qemuMonitorPtr mon,
6ae9ed
 
6ae9ed
     QEMU_CHECK_MONITOR(mon);
6ae9ed
 
6ae9ed
-    /* there won't be a direct replacement for drive_del in QMP */
6ae9ed
-    return qemuMonitorTextDriveDel(mon, drivestr);
6ae9ed
+    if (mon->json)
6ae9ed
+        return qemuMonitorJSONDriveDel(mon, drivestr);
6ae9ed
+    else
6ae9ed
+        return qemuMonitorTextDriveDel(mon, drivestr);
6ae9ed
 }
6ae9ed
 
6ae9ed
 
3e5111
@@ -3195,8 +3197,10 @@ qemuMonitorAddDrive(qemuMonitorPtr mon,
6ae9ed
 
6ae9ed
     QEMU_CHECK_MONITOR(mon);
6ae9ed
 
6ae9ed
-    /* there won't ever be a direct QMP replacement for this function */
6ae9ed
-    return qemuMonitorTextAddDrive(mon, drivestr);
6ae9ed
+    if (mon->json)
6ae9ed
+        return qemuMonitorJSONAddDrive(mon, drivestr);
6ae9ed
+    else
6ae9ed
+        return qemuMonitorTextAddDrive(mon, drivestr);
6ae9ed
 }
6ae9ed
 
6ae9ed
 
c401cc
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
3e5111
index 2010657e3..6fcf57cd1 100644
c401cc
--- a/src/qemu/qemu_monitor_json.c
c401cc
+++ b/src/qemu/qemu_monitor_json.c
3e5111
@@ -3807,6 +3807,112 @@ int qemuMonitorJSONDelObject(qemuMonitorPtr mon,
6ae9ed
 }
6ae9ed
 
6ae9ed
 
6ae9ed
+int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
6ae9ed
+                            const char *drivestr)
6ae9ed
+{
c401cc
+    int ret = -1;
c401cc
+    virJSONValuePtr cmd;
c401cc
+    virJSONValuePtr reply = NULL;
c401cc
+    virJSONValuePtr args;
c401cc
+
c401cc
+    cmd = qemuMonitorJSONMakeCommand("__com.redhat_drive_add",
c401cc
+                                     NULL);
c401cc
+    if (!cmd)
c401cc
+        return -1;
c401cc
+
c401cc
+    args = qemuMonitorJSONKeywordStringToJSON(drivestr, "type");
c401cc
+    if (!args)
c401cc
+        goto cleanup;
c401cc
+
c401cc
+    /* __com.redhat_drive_add rejects the 'if' key */
c401cc
+    virJSONValueObjectRemoveKey(args, "if", NULL);
c401cc
+
c401cc
+    if (virJSONValueObjectAppend(cmd, "arguments", args) < 0) {
c401cc
+        virReportOOMError();
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+    args = NULL; /* cmd owns reference to args now */
c401cc
+
9119d9
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
c401cc
+        goto cleanup;
c401cc
+
c401cc
+    if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
c401cc
+        virJSONValueFree(cmd);
c401cc
+        virJSONValueFree(reply);
9119d9
+        cmd = reply = NULL;
c401cc
+
c401cc
+        VIR_DEBUG("__com.redhat_drive_add command not found,"
9119d9
+                  " trying upstream way");
c401cc
+    } else {
c401cc
+        ret = qemuMonitorJSONCheckError(cmd, reply);
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
+    /* Upstream approach */
6ae9ed
+    /* there won't be a direct replacement for drive_add in QMP */
c401cc
+    ret = qemuMonitorTextAddDrive(mon, drivestr);
c401cc
+
3e5111
+ cleanup:
c401cc
+    virJSONValueFree(args);
c401cc
+    virJSONValueFree(cmd);
c401cc
+    virJSONValueFree(reply);
c401cc
+    return ret;
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
+int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
6ae9ed
+                            const char *drivestr)
6ae9ed
+{
6ae9ed
+    int ret;
c401cc
+    virJSONValuePtr cmd;
c401cc
+    virJSONValuePtr reply = NULL;
6ae9ed
+
c401cc
+    VIR_DEBUG("drivestr=%s", drivestr);
c401cc
+    cmd = qemuMonitorJSONMakeCommand("__com.redhat_drive_del",
c401cc
+                                     "s:id", drivestr,
c401cc
+                                     NULL);
c401cc
+    if (!cmd)
c401cc
+        return -1;
9119d9
+
c401cc
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
c401cc
+        goto cleanup;
c401cc
+
c401cc
+    if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
c401cc
+        virJSONValueFree(cmd);
c401cc
+        virJSONValueFree(reply);
9119d9
+        cmd = reply = NULL;
c401cc
+
c401cc
+        VIR_DEBUG("__com.redhat_drive_del command not found,"
9119d9
+                  " trying upstream way");
c401cc
+    } else if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
c401cc
+        /* NB: device not found errors mean the drive was
c401cc
+         * auto-deleted and we ignore the error */
c401cc
+        ret = 0;
c401cc
+        goto cleanup;
c401cc
+    } else {
c401cc
+        ret = qemuMonitorJSONCheckError(cmd, reply);
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
+    /* Upstream approach */
6ae9ed
+    /* there won't be a direct replacement for drive_del in QMP */
6ae9ed
+    if ((ret = qemuMonitorTextDriveDel(mon, drivestr)) < 0) {
6ae9ed
+        virErrorPtr err = virGetLastError();
6ae9ed
+        if (err && err->code == VIR_ERR_OPERATION_UNSUPPORTED) {
6ae9ed
+            VIR_ERROR("%s",
6ae9ed
+                      _("deleting disk is not supported.  "
6ae9ed
+                        "This may leak data if disk is reassigned"));
6ae9ed
+            ret = 1;
6ae9ed
+            virResetLastError();
6ae9ed
+        }
6ae9ed
+    }
c401cc
+
3e5111
+ cleanup:
c401cc
+    virJSONValueFree(cmd);
c401cc
+    virJSONValueFree(reply);
6ae9ed
+    return ret;
6ae9ed
+}
6ae9ed
+
6ae9ed
 int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
6ae9ed
                                       const char *alias,
6ae9ed
                                       const char *passphrase)
6ae9ed
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
3e5111
index fb697033c..696aaeffc 100644
6ae9ed
--- a/src/qemu/qemu_monitor_json.h
6ae9ed
+++ b/src/qemu/qemu_monitor_json.h
3e5111
@@ -233,6 +233,12 @@ int qemuMonitorJSONAddObject(qemuMonitorPtr mon,
6ae9ed
 int qemuMonitorJSONDelObject(qemuMonitorPtr mon,
6ae9ed
                              const char *objalias);
c401cc
 
6ae9ed
+int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
6ae9ed
+                            const char *drivestr);
6ae9ed
+
6ae9ed
+int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
6ae9ed
+                            const char *drivestr);
6ae9ed
+
6ae9ed
 int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
6ae9ed
                                       const char *alias,
6ae9ed
                                       const char *passphrase);
9119d9
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
3e5111
index cdeb3f1bf..2e1afeea9 100644
9119d9
--- a/tests/qemuhotplugtest.c
9119d9
+++ b/tests/qemuhotplugtest.c
3e5111
@@ -658,6 +658,14 @@ mymain(void)
9119d9
     "    }"                                                 \
9119d9
     "}\r\n"
9119d9
 
9119d9
+#define QMP_NOT_FOUND \
9119d9
+    "{" \
9119d9
+    "    \"error\": {" \
9119d9
+    "        \"class\": \"CommandNotFound\"," \
9119d9
+    "        \"desc\": \"The command has not been found\"" \
9119d9
+    "    }" \
9119d9
+    "}"
9119d9
+
9119d9
     DO_TEST_UPDATE("graphics-spice", "graphics-spice-nochange", false, false, NULL);
9119d9
     DO_TEST_UPDATE("graphics-spice-timeout", "graphics-spice-timeout-nochange", false, false,
9119d9
                    "set_password", QMP_OK, "expire_password", QMP_OK);
3e5111
@@ -678,67 +686,135 @@ mymain(void)
9119d9
                    "chardev-remove", QMP_OK);
9119d9
 
3e5111
     DO_TEST_ATTACH("base-live", "disk-virtio", false, true,
9119d9
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP("OK\\r\\n"),
9119d9
                    "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-live", "disk-virtio", false, false,
9119d9
                    "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
9119d9
 
3e5111
+    DO_TEST_ATTACH("base-live", "disk-virtio", false, true,
9119d9
+                   "__com.redhat_drive_add", QMP_OK,
9119d9
+                   "device_add", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-virtio", false, false,
9119d9
+                   "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
9119d9
+
3e5111
     DO_TEST_ATTACH_EVENT("base-live", "disk-virtio", false, true,
9119d9
+                         "__com.redhat_drive_add", QMP_NOT_FOUND,
9119d9
                          "human-monitor-command", HMP("OK\\r\\n"),
9119d9
                          "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-live", "disk-virtio", true, true,
9119d9
                    "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
3e5111
     DO_TEST_DETACH("base-live", "disk-virtio", false, false,
9119d9
                    "device_del", QMP_DEVICE_DELETED("virtio-disk4") QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
9119d9
 
3e5111
+    DO_TEST_ATTACH_EVENT("base-live", "disk-virtio", false, true,
9119d9
+                         "__com.redhat_drive_add", QMP_OK,
9119d9
+                         "device_add", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-virtio", true, true,
9119d9
+                   "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-virtio", false, false,
9119d9
+                   "device_del", QMP_DEVICE_DELETED("virtio-disk4") QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
9119d9
+
3e5111
     DO_TEST_ATTACH("base-live", "disk-usb", false, true,
9119d9
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP("OK\\r\\n"),
9119d9
                    "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-live", "disk-usb", false, false,
9119d9
                    "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
9119d9
 
3e5111
+    DO_TEST_ATTACH("base-live", "disk-usb", false, true,
9119d9
+                   "__com.redhat_drive_add", QMP_OK,
9119d9
+                   "device_add", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-usb", false, false,
9119d9
+                   "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
9119d9
+
3e5111
     DO_TEST_ATTACH_EVENT("base-live", "disk-usb", false, true,
9119d9
+                         "__com.redhat_drive_add", QMP_NOT_FOUND,
9119d9
                          "human-monitor-command", HMP("OK\\r\\n"),
9119d9
                          "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-live", "disk-usb", true, true,
9119d9
                    "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
3e5111
     DO_TEST_DETACH("base-live", "disk-usb", false, false,
9119d9
                    "device_del", QMP_DEVICE_DELETED("usb-disk16") QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
9119d9
 
3e5111
+    DO_TEST_ATTACH_EVENT("base-live", "disk-usb", false, true,
9119d9
+                         "__com.redhat_drive_add", QMP_OK,
9119d9
+                         "device_add", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-usb", true, true,
9119d9
+                   "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-usb", false, false,
9119d9
+                   "device_del", QMP_DEVICE_DELETED("usb-disk16") QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
9119d9
+
3e5111
     DO_TEST_ATTACH("base-live", "disk-scsi", false, true,
9119d9
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP("OK\\r\\n"),
9119d9
                    "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-live", "disk-scsi", false, false,
9119d9
                    "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
9119d9
 
3e5111
+    DO_TEST_ATTACH("base-live", "disk-scsi", false, true,
9119d9
+                   "__com.redhat_drive_add", QMP_OK,
9119d9
+                   "device_add", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-scsi", false, false,
9119d9
+                   "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
9119d9
+
3e5111
     DO_TEST_ATTACH_EVENT("base-live", "disk-scsi", false, true,
9119d9
+                         "__com.redhat_drive_add", QMP_NOT_FOUND,
9119d9
                          "human-monitor-command", HMP("OK\\r\\n"),
9119d9
                          "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-live", "disk-scsi", true, true,
9119d9
                    "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
3e5111
     DO_TEST_DETACH("base-live", "disk-scsi", false, false,
9119d9
                    "device_del", QMP_DEVICE_DELETED("scsi0-0-0-5") QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
9119d9
                    "human-monitor-command", HMP(""));
9119d9
 
3e5111
+    DO_TEST_ATTACH_EVENT("base-live", "disk-scsi", false, true,
9119d9
+                         "__com.redhat_drive_add", QMP_OK,
9119d9
+                         "device_add", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-scsi", true, true,
9119d9
+                   "device_del", QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
3e5111
+    DO_TEST_DETACH("base-live", "disk-scsi", false, false,
9119d9
+                   "device_del", QMP_DEVICE_DELETED("scsi0-0-0-5") QMP_OK,
9119d9
+                   "__com.redhat_drive_del", QMP_OK);
9119d9
+
3e5111
     DO_TEST_ATTACH("base-without-scsi-controller-live", "disk-scsi-2", false, true,
6ae9ed
                    /* Four controllers added */
6ae9ed
                    "device_add", QMP_OK,
6ae9ed
                    "device_add", QMP_OK,
6ae9ed
                    "device_add", QMP_OK,
6ae9ed
                    "device_add", QMP_OK,
6ae9ed
-                   "human-monitor-command", HMP("OK\\r\\n"),
6ae9ed
                    /* Disk added */
6ae9ed
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
6ae9ed
+                   "human-monitor-command", HMP("OK\\r\\n"),
6ae9ed
                    "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-with-scsi-controller-live", "disk-scsi-2", false, false,
6ae9ed
                    "device_del", QMP_OK,
6ae9ed
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
6ae9ed
                    "human-monitor-command", HMP(""));
6ae9ed
 
3e5111
     DO_TEST_ATTACH_EVENT("base-without-scsi-controller-live", "disk-scsi-2", false, true,
3e5111
@@ -747,14 +823,17 @@ mymain(void)
6ae9ed
                          "device_add", QMP_OK,
6ae9ed
                          "device_add", QMP_OK,
6ae9ed
                          "device_add", QMP_OK,
6ae9ed
-                         "human-monitor-command", HMP("OK\\r\\n"),
6ae9ed
                          /* Disk added */
6ae9ed
+                         "__com.redhat_drive_add", QMP_NOT_FOUND,
6ae9ed
+                         "human-monitor-command", HMP("OK\\r\\n"),
6ae9ed
                          "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-with-scsi-controller-live", "disk-scsi-2", true, true,
6ae9ed
                    "device_del", QMP_OK,
6ae9ed
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
6ae9ed
                    "human-monitor-command", HMP(""));
3e5111
     DO_TEST_DETACH("base-with-scsi-controller-live", "disk-scsi-2", false, false,
6ae9ed
                    "device_del", QMP_DEVICE_DELETED("scsi3-0-5-7") QMP_OK,
6ae9ed
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
6ae9ed
                    "human-monitor-command", HMP(""));
6ae9ed
 
3e5111
     DO_TEST_ATTACH("base-live", "qemu-agent", false, true,
3e5111
@@ -765,38 +844,47 @@ mymain(void)
3e5111
                    "chardev-remove", QMP_OK);
3e5111
 
3e5111
     DO_TEST_ATTACH("base-ccw-live", "ccw-virtio", false, true,
3e5111
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP("OK\\r\\n"),
3e5111
                    "device_add", QMP_OK);
3e5111
     DO_TEST_DETACH("base-ccw-live", "ccw-virtio", false, false,
3e5111
                    "device_del", QMP_OK,
3e5111
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP(""));
3e5111
 
3e5111
     DO_TEST_ATTACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2", false, true,
3e5111
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP("OK\\r\\n"),
3e5111
                    "device_add", QMP_OK);
3e5111
 
3e5111
     DO_TEST_DETACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2", false, false,
3e5111
                    "device_del", QMP_OK,
3e5111
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP(""));
3e5111
 
3e5111
     DO_TEST_ATTACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2-explicit", false, true,
3e5111
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP("OK\\r\\n"),
3e5111
                    "device_add", QMP_OK);
3e5111
 
3e5111
     DO_TEST_DETACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2-explicit", false, false,
3e5111
                    "device_del", QMP_OK,
3e5111
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP(""));
3e5111
 
3e5111
     /* Attach a second device, then detach the first one. Then attach the first one again. */
3e5111
     DO_TEST_ATTACH("base-ccw-live-with-ccw-virtio", "ccw-virtio-2-explicit", false, true,
3e5111
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP("OK\\r\\n"),
3e5111
                    "device_add", QMP_OK);
3e5111
 
3e5111
     DO_TEST_DETACH("base-ccw-live-with-2-ccw-virtio", "ccw-virtio-1-explicit", false, true,
3e5111
                    "device_del", QMP_OK,
3e5111
+                   "__com.redhat_drive_del", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP(""));
3e5111
 
3e5111
     DO_TEST_ATTACH("base-ccw-live-with-2-ccw-virtio", "ccw-virtio-1-reverse", false, false,
3e5111
+                   "__com.redhat_drive_add", QMP_NOT_FOUND,
3e5111
                    "human-monitor-command", HMP("OK\\r\\n"),
3e5111
                    "device_add", QMP_OK);
3e5111
 
c401cc
-- 
3e5111
2.12.2
c401cc