qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 3/4] qmp: Add "snapshot=" option to nbd-server-a


From: Fam Zheng
Subject: [Qemu-devel] [RFC PATCH 3/4] qmp: Add "snapshot=" option to nbd-server-add
Date: Mon, 29 Jul 2013 12:25:31 +0800

With drive-backup block job, we can have a point-in-time snapshot of a
device. With snapshot=on, a backup block job is started on the device to
do CoW to a temporary image and this image is exported to nbd. The image
is deleted after nbd server stops.

Signed-off-by: Fam Zheng <address@hidden>
---
 blockdev-nbd.c   | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 hmp.c            |  5 ++--
 qapi-schema.json |  3 ++-
 qmp-commands.hx  |  2 +-
 4 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index c75df19..f12b57c 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -17,6 +17,8 @@
 #include "qmp-commands.h"
 #include "trace.h"
 #include "block/nbd.h"
+#include "block/block_int.h"
+#include "block/block.h"
 #include "qemu/sockets.h"
 
 static int server_fd = -1;
@@ -78,8 +80,62 @@ static void nbd_server_put_ref(NBDExport *exp)
     }
 }
 
+static void snapshot_drive_backup_cb(void *opaque, int ret)
+{
+    BlockDriverState *bs = opaque;
+    bs->backing_hd = NULL;
+}
+
+/* create a point-in-time snapshot BDS from an existing BDS */
+static BlockDriverState *nbd_create_snapshot(BlockDriverState *orig_bs)
+{
+    int ret;
+    char filename[1024];
+    BlockDriver *drv;
+    BlockDriverState *bs;
+    QEMUOptionParameter *options;
+    Error *local_err = NULL;
+
+    bs = bdrv_new("");
+    ret = get_tmp_filename(filename, sizeof(filename));
+    if (ret < 0) {
+        goto err;
+    }
+    drv = bdrv_find_format("qcow2");
+    if (drv < 0) {
+        goto err;
+    }
+    options = parse_option_parameters("", drv->create_options, NULL);
+    set_option_parameter_int(options, BLOCK_OPT_SIZE, bdrv_getlength(orig_bs));
+
+    ret = bdrv_create(drv, filename, options);
+    if (ret < 0) {
+        goto err;
+    }
+    ret = bdrv_open(bs, filename, NULL, BDRV_O_RDWR, drv);
+    if (ret < 0) {
+        goto err;
+    }
+    bs->backing_hd = orig_bs;
+
+    backup_start(orig_bs, bs, 1,
+            MIRROR_SYNC_MODE_NONE,
+            BLOCKDEV_ON_ERROR_REPORT,
+            BLOCKDEV_ON_ERROR_REPORT,
+            snapshot_drive_backup_cb, bs, &local_err);
+    if (error_is_set(&local_err)) {
+        goto err;
+    }
+    return bs;
+
+err:
+    bdrv_delete(bs);
+    unlink(filename);
+    return NULL;
+}
+
 void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
-                        Error **errp)
+                        bool has_snapshot, bool snapshot, Error **errp)
 {
     BlockDriverState *bs;
     NBDExport *exp;
@@ -104,21 +160,37 @@ void qmp_nbd_server_add(const char *device, bool 
has_writable, bool writable,
     if (!has_writable) {
         writable = false;
     }
+
+    if (!has_snapshot) {
+        snapshot = false;
+    }
+
     if (bdrv_is_read_only(bs)) {
         writable = false;
     }
 
+    if (snapshot) {
+        bs = nbd_create_snapshot(bs);
+        if (!bs) {
+            error_setg(errp, "Can't create snapshot for device");
+            return;
+        }
+    }
+
     exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
                          nbd_server_put_ref);
 
     nbd_export_set_name(exp, device);
-    drive_get_ref(drive_get_by_blockdev(bs));
+    if (!snapshot) {
+        drive_get_ref(drive_get_by_blockdev(bs));
+    }
 
     n = g_malloc0(sizeof(NBDCloseNotifier));
     n->n.notify = nbd_close_notifier;
     n->exp = exp;
     bdrv_add_close_notifier(bs, &n->n);
     QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
+    return;
 }
 
 void qmp_nbd_server_stop(Error **errp)
diff --git a/hmp.c b/hmp.c
index c45514b..5cc97fe 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1440,7 +1440,8 @@ void hmp_nbd_server_start(Monitor *mon, const QDict 
*qdict)
             continue;
         }
 
-        qmp_nbd_server_add(info->value->device, true, writable, &local_err);
+        qmp_nbd_server_add(info->value->device, true, writable, false, false,
+                           &local_err);
 
         if (local_err != NULL) {
             qmp_nbd_server_stop(NULL);
@@ -1460,7 +1461,7 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
     int writable = qdict_get_try_bool(qdict, "writable", 0);
     Error *local_err = NULL;
 
-    qmp_nbd_server_add(device, true, writable, &local_err);
+    qmp_nbd_server_add(device, true, writable, false, false, &local_err);
 
     if (local_err != NULL) {
         hmp_handle_error(mon, &local_err);
diff --git a/qapi-schema.json b/qapi-schema.json
index f82d829..bfdbe33 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3225,7 +3225,8 @@
 #
 # Since: 1.3.0
 ##
-{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool'} }
+{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool',
+                                        '*snapshot': 'bool'} }
 
 ##
 # @nbd-server-stop:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 2e59b0d..e398d88 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2871,7 +2871,7 @@ EQMP
     },
     {
         .name       = "nbd-server-add",
-        .args_type  = "device:B,writable:b?",
+        .args_type  = "device:B,writable:b?,snapshot:b?",
         .mhandler.cmd_new = qmp_marshal_input_nbd_server_add,
     },
     {
-- 
1.8.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]