From 636180695ffe06b948b599fcb6788061cd9cc383 Mon Sep 17 00:00:00 2001
From: Jeffrey Cody <jcody@redhat.com>
Date: Tue, 10 Jan 2012 14:39:00 +0100
Subject: [PATCH 6/7] Revert "QMP/HMP: Drop the live snapshot commands"

RH-Author: Jeffrey Cody <jcody@redhat.com>
Message-id: <1326206340.13202.16.camel@jefflaptop>
Patchwork-id: 36324
O-Subject: [RHEL6.3 qemu-kvm PATCH v2 1/2] Revert "QMP/HMP: Drop the live snapshot commands"
Bugzilla: 752003
RH-Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
RH-Acked-by: Alex Williamson <alex.williamson@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>

This reverts downstream rhel6 commit 1ff41c0, which removed the
do_snapshot_blkdev command from blockdev.c and qemu-monitor.hx.

This is moving us closer to upstream; there are two differences:

1) In blockdev.c, qemu_aio_flush() is still used instead of
   bdrv_drain_all(), because bdrv_drain_all() was not introduced
   upstream until commit 922453b (which converted qemu_aio_flush()
   calls to bdrv_drain_all() calls)

2) The QMP & HMP commands are in qemu-monitor.hx, instead of broken
   out into qmp-commands.hx and hmp-commmands.hx

BZ 769111
Signed-off-by: Jeff Cody <jcody@redhat.com>
---
 blockdev.c      |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-monitor.hx |   53 +++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+), 0 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 blockdev.c      |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-monitor.hx |   53 +++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+), 0 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index d07bf67..067bbee 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -832,6 +832,85 @@ void do_commit(Monitor *mon, const QDict *qdict)
     }
 }
 
+int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *filename = qdict_get_try_str(qdict, "snapshot-file");
+    const char *format = qdict_get_try_str(qdict, "format");
+    BlockDriverState *bs;
+    BlockDriver *drv, *old_drv, *proto_drv;
+    int ret = 0;
+    int flags;
+    char old_filename[1024];
+
+    if (!filename) {
+        qerror_report(QERR_MISSING_PARAMETER, "snapshot-file");
+        ret = -1;
+        goto out;
+    }
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        ret = -1;
+        goto out;
+    }
+
+    pstrcpy(old_filename, sizeof(old_filename), bs->filename);
+
+    old_drv = bs->drv;
+    flags = bs->open_flags;
+
+    if (!format) {
+        format = "qcow2";
+    }
+
+    drv = bdrv_find_format(format);
+    if (!drv) {
+        qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
+        ret = -1;
+        goto out;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
+        ret = -1;
+        goto out;
+    }
+
+    ret = bdrv_img_create(filename, format, bs->filename,
+                          bs->drv->format_name, NULL, -1, flags);
+    if (ret) {
+        goto out;
+    }
+
+    qemu_aio_flush();
+    bdrv_flush(bs);
+
+    bdrv_close(bs);
+    ret = bdrv_open(bs, filename, flags, drv);
+    /*
+     * If reopening the image file we just created fails, fall back
+     * and try to re-open the original image. If that fails too, we
+     * are in serious trouble.
+     */
+    if (ret != 0) {
+        ret = bdrv_open(bs, old_filename, flags, old_drv);
+        if (ret != 0) {
+            qerror_report(QERR_OPEN_FILE_FAILED, old_filename);
+        } else {
+            qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        }
+    }
+out:
+    if (ret) {
+        ret = -1;
+    }
+
+    return ret;
+}
+
 static void monitor_print_block_stream(Monitor *mon, const QObject *data)
 {
     QDict *stream;
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index b771797..149c3a0 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -1385,6 +1385,25 @@ Example:
 EQMP
 
     {
+        .name       = "snapshot_blkdev",
+        .args_type  = "device:B,snapshot-file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .help       = "initiates a live snapshot\n\t\t\t"
+                      "of device. If a new image file is specified, the\n\t\t\t"
+                      "new image file will become the new root image.\n\t\t\t"
+                      "If format is specified, the snapshot file will\n\t\t\t"
+                      "be created in that format. Otherwise the\n\t\t\t"
+                      "snapshot will be internal! (currently unsupported)",
+        .mhandler.cmd_new = do_snapshot_blkdev,
+    },
+
+STEXI
+@item snapshot_blkdev
+@findex snapshot_blkdev
+Snapshot device, using snapshot file as target if provided
+ETEXI
+
+    {
         .name       = "block_resize",
         .args_type  = "device:B,size:o",
         .params     = "device size",
@@ -1603,6 +1622,40 @@ Remove host-to-guest TCP or UDP redirection.
 ETEXI
 
     {
+        .name       = "blockdev-snapshot-sync",
+        .args_type  = "device:B,snapshot-file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_snapshot_blkdev,
+    },
+
+SQMP
+blockdev-snapshot-sync
+----------------------
+
+Synchronous snapshot of a block device. snapshot-file specifies the
+target of the new image. If the file exists, or if it is a device, the
+snapshot will be created in the existing file/device. If does not
+exist, a new file will be created. format specifies the format of the
+snapshot image, default is qcow2.
+
+Arguments:
+
+- "device": device name to snapshot (json-string)
+- "snapshot-file": name of new image file (json-string)
+- "format": format of new image (json-string, optional)
+
+Example:
+
+-> { "execute": "blockdev-snapshot", "arguments": { "device": "ide-hd0",
+                                                    "snapshot-file":
+                                                    "/some/place/my-image",
+                                                    "format": "qcow2" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "balloon",
         .args_type  = "value:M",
         .params     = "target",
-- 
1.7.7.5

