c401cc
From 673fabafb0dc8eca749e9b0eae13645afe752e42 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <673fabafb0dc8eca749e9b0eae13645afe752e42.1386932213.git.jdenemar@redhat.com>
c401cc
From: "Daniel P. Berrange" <berrange@redhat.com>
c401cc
Date: Fri, 17 Dec 2010 14:55:38 +0100
c401cc
Subject: [PATCH] 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
---
c401cc
 src/qemu/qemu_monitor_json.c | 79 +++++++++++++++++++++++++++++++++++++++++++-
c401cc
 1 file changed, 78 insertions(+), 1 deletion(-)
c401cc
c401cc
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
c401cc
index 18497e3..7b7992f 100644
c401cc
--- a/src/qemu/qemu_monitor_json.c
c401cc
+++ b/src/qemu/qemu_monitor_json.c
c401cc
@@ -3113,9 +3113,53 @@ cleanup:
c401cc
 int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
c401cc
                             const char *drivestr)
c401cc
 {
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
+
c401cc
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply) < 0))
c401cc
+        goto cleanup;
c401cc
+
c401cc
+    if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
c401cc
+        virJSONValueFree(cmd);
c401cc
+        virJSONValueFree(reply);
c401cc
+
c401cc
+        VIR_DEBUG("__com.redhat_drive_add command not found,"
c401cc
+                   " trying upstream way");
c401cc
+    } else {
c401cc
+        ret = qemuMonitorJSONCheckError(cmd, reply);
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
+    /* Upstream approach */
c401cc
     /* XXX Update to use QMP, if QMP ever adds support for drive_add */
c401cc
     VIR_DEBUG("drive_add command not found, trying HMP");
c401cc
-    return qemuMonitorTextAddDrive(mon, drivestr);
c401cc
+    ret = qemuMonitorTextAddDrive(mon, drivestr);
c401cc
+
c401cc
+cleanup:
c401cc
+    virJSONValueFree(args);
c401cc
+    virJSONValueFree(cmd);
c401cc
+    virJSONValueFree(reply);
c401cc
+    return ret;
c401cc
 }
c401cc
 
c401cc
 
c401cc
@@ -3123,7 +3167,36 @@ int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
c401cc
                             const char *drivestr)
c401cc
 {
c401cc
     int ret;
c401cc
+    virJSONValuePtr cmd;
c401cc
+    virJSONValuePtr reply = NULL;
c401cc
+
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;
c401cc
 
c401cc
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
c401cc
+        goto cleanup;
c401cc
+
c401cc
+    if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
c401cc
+        virJSONValueFree(cmd);
c401cc
+        virJSONValueFree(reply);
c401cc
+
c401cc
+        VIR_DEBUG("__com.redhat_drive_del command not found,"
c401cc
+                   " 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 */
c401cc
     /* XXX Update to use QMP, if QMP ever adds support for drive_del */
c401cc
     VIR_DEBUG("drive_del command not found, trying HMP");
c401cc
     if ((ret = qemuMonitorTextDriveDel(mon, drivestr)) < 0) {
c401cc
@@ -3136,6 +3209,10 @@ int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
c401cc
             virResetLastError();
c401cc
         }
c401cc
     }
c401cc
+
c401cc
+cleanup:
c401cc
+    virJSONValueFree(cmd);
c401cc
+    virJSONValueFree(reply);
c401cc
     return ret;
c401cc
 }
c401cc
 
c401cc
-- 
c401cc
1.8.5.1
c401cc