qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 6/6] snapshot: human monitor interface


From: Wenchao Xia
Subject: [Qemu-devel] [PATCH 6/6] snapshot: human monitor interface
Date: Mon, 17 Dec 2012 14:25:09 +0800

  This patch add support in human monitor to create/delete/check
internal snapshot on a single blk device.
  To make info command get parameter, added a new info handler
type which can take QDict as parameter.

Signed-off-by: Wenchao Xia <address@hidden>
---
 hmp-commands.hx |   50 +++++++++++++++++++++++++++++++++++++-------------
 hmp.c           |   30 +++++++++++++++++++++++++-----
 hmp.h           |    1 +
 monitor.c       |   21 +++++++++++++++------
 savevm.c        |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 sysemu.h        |    2 +-
 6 files changed, 133 insertions(+), 26 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 010b8c9..ee74723 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -983,17 +983,22 @@ ETEXI
 
     {
         .name       = "snapshot_blkdev",
-        .args_type  = "reuse:-n,device:B,snapshot-file:s?,format:s?",
-        .params     = "[-n] 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).\n\t\t\t"
-                      "The default format is qcow2.  The -n flag requests 
QEMU\n\t\t\t"
-                      "to reuse the image found in new-image-file, instead 
of\n\t\t\t"
-                      "recreating it from scratch.",
+        .args_type  = 
"internal:-i,reuse:-n,device:B,snapshot-file:s?,format:s?",
+        .params     = "[-i] [-n] device [new-image-file] [format]",
+        .help       = "initiates a live snapshot of device.\n\t\t\t"
+                      "  The -i flag requests QEMU to create internal 
snapshot\n\t\t\t"
+                      "instead of external one.\n\t\t\t"
+                      "  The -n flag requests QEMU to use existing 
snapshot\n\t\t\t"
+                      "instead of creating new snapshot, which would fails 
if\n\t\t\t"
+                      "snapshot does not exist ahead.\n\t\t\t"
+                      "  new-image-file is the snapshot's name, in external 
case\n\t\t\t"
+                      "it is the new image's name which will become the new 
root\n\t\t\t"
+                      "image and must be specified, in internal case it is 
the\n\t\t\t"
+                      "record's name and if not specified QEMU will 
create\n\t\t\t"
+                      "internal snapshot with name generated according to 
time.\n\t\t\t"
+                      "  format is only valid in external case, which is the 
new\n\t\t\t"
+                      "snapshot image's format. If not sepcified default 
format\n\t\t\t"
+                      "qcow2 will be used.",
         .mhandler.cmd = hmp_snapshot_blkdev,
     },
 
@@ -1004,6 +1009,25 @@ Snapshot device, using snapshot file as target if 
provided
 ETEXI
 
     {
+        .name       = "snapshot_delete_blkdev",
+        .args_type  = "internal:-i,device:B,snapshot-file:s",
+        .params     = "[-i] device new-image-file",
+        .help       = "delete a snapshot  synchronous.\n\t\t\t"
+                      "  The -i flag requests QEMU to delete internal 
snapshot\n\t\t\t"
+                      "instead of external one.\n\t\t\t"
+                      "  new-image-file is the snapshot's name, in external 
case\n\t\t\t"
+                      "it is the image's name which is not supported 
now.\n\t\t\t"
+                      "in internal case it is the snapshot record's id or 
name.",
+        .mhandler.cmd = hmp_snapshot_delete_blkdev,
+    },
+
+STEXI
address@hidden snapshot_delete_blkdev
address@hidden snapshot_delete_blkdev
+Delete a snapshot on a block device.
+ETEXI
+
+    {
         .name       = "drive_mirror",
         .args_type  = "reuse:-n,full:-f,device:B,target:s,format:s?",
         .params     = "[-n] [-f] device target [format]",
@@ -1486,8 +1510,8 @@ ETEXI
 
     {
         .name       = "info",
-        .args_type  = "item:s?",
-        .params     = "[subcommand]",
+        .args_type  = "item:s?,params:s?",
+        .params     = "[subcommand] [params]",
         .help       = "show various information about the system state",
         .mhandler.cmd = do_info,
     },
diff --git a/hmp.c b/hmp.c
index 180ba2b..f247f51 100644
--- a/hmp.c
+++ b/hmp.c
@@ -806,20 +806,40 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
     const char *filename = qdict_get_try_str(qdict, "snapshot-file");
     const char *format = qdict_get_try_str(qdict, "format");
     int reuse = qdict_get_try_bool(qdict, "reuse", 0);
+    int internal = qdict_get_try_bool(qdict, "internal", 0);
     enum NewImageMode mode;
+    enum SnapshotType type;
     Error *errp = NULL;
 
-    if (!filename) {
-        /* In the future, if 'snapshot-file' is not specified, the snapshot
-           will be taken internally. Today it's actually required. */
+    if ((!internal) && (!filename)) {
+        /* in external case filename must be set, should we generate
+         it automatically? */
         error_set(&errp, QERR_MISSING_PARAMETER, "snapshot-file");
         hmp_handle_error(mon, &errp);
         return;
     }
-
+    type = internal ? SNAPSHOT_TYPE_INTERNAL : SNAPSHOT_TYPE_EXTERNAL;
     mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
     qmp_blockdev_snapshot_sync(device, filename, !!format, format,
-                               true, mode, &errp);
+                               true, mode, true, type, &errp);
+    hmp_handle_error(mon, &errp);
+}
+
+void hmp_snapshot_delete_blkdev(Monitor *mon, const QDict *qdict)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *filename = qdict_get_try_str(qdict, "snapshot-file");
+    int internal = qdict_get_try_bool(qdict, "internal", 0);
+    enum SnapshotType type;
+    Error *errp = NULL;
+
+    if (!internal) {
+        error_setg(&errp, "external snapshot delete not supported now.");
+        hmp_handle_error(mon, &errp);
+        return;
+    }
+    type = internal ? SNAPSHOT_TYPE_INTERNAL : SNAPSHOT_TYPE_EXTERNAL;
+    qmp_blockdev_snapshot_delete_sync(device, filename, true, type, &errp);
     hmp_handle_error(mon, &errp);
 }
 
diff --git a/hmp.h b/hmp.h
index 0ab03be..2ea67be 100644
--- a/hmp.h
+++ b/hmp.h
@@ -51,6 +51,7 @@ void hmp_block_passwd(Monitor *mon, const QDict *qdict);
 void hmp_balloon(Monitor *mon, const QDict *qdict);
 void hmp_block_resize(Monitor *mon, const QDict *qdict);
 void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
+void hmp_snapshot_delete_blkdev(Monitor *mon, const QDict *qdict);
 void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index c0e32d6..81de470 100644
--- a/monitor.c
+++ b/monitor.c
@@ -124,11 +124,14 @@ typedef struct mon_cmd_t {
     void (*user_print)(Monitor *mon, const QObject *data);
     union {
         void (*info)(Monitor *mon);
+        void (*info_qdict)(Monitor *mon, const QDict *qdict);
         void (*cmd)(Monitor *mon, const QDict *qdict);
-        int  (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+        int  (*cmd_new)(Monitor *mon, const QDict *params,
+                        QObject **ret_data);
         int  (*cmd_async)(Monitor *mon, const QDict *params,
                           MonitorCompletion *cb, void *opaque);
     } mhandler;
+    int info_cmd_need_qdict;
     int flags;
 } mon_cmd_t;
 
@@ -824,7 +827,11 @@ static void do_info(Monitor *mon, const QDict *qdict)
         goto help;
     }
 
-    cmd->mhandler.info(mon);
+    if (cmd->info_cmd_need_qdict) {
+        cmd->mhandler.info_qdict(mon, qdict);
+    } else {
+        cmd->mhandler.info(mon);
+    }
     return;
 
 help:
@@ -2605,10 +2612,12 @@ static mon_cmd_t info_cmds[] = {
     },
     {
         .name       = "snapshots",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the currently saved VM snapshots",
-        .mhandler.info = do_info_snapshots,
+        .args_type  = "device:B?",
+        .params     = "[device]",
+        .help       = "show the currently saved VM snapshots or snapshots on "
+                      "a single device.",
+        .mhandler.info_qdict = do_info_snapshots,
+        .info_cmd_need_qdict = 1,
     },
     {
         .name       = "status",
diff --git a/savevm.c b/savevm.c
index c027529..5982aa9 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2336,7 +2336,7 @@ void do_delvm(Monitor *mon, const QDict *qdict)
     }
 }
 
-void do_info_snapshots(Monitor *mon)
+static void do_info_snapshots_vm(Monitor *mon)
 {
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
@@ -2400,6 +2400,59 @@ void do_info_snapshots(Monitor *mon)
 
 }
 
+static void do_info_snapshots_blk(Monitor *mon, const char *device)
+{
+    BlockDriverState *bs;
+    QEMUSnapshotInfo *sn_tab, *sn;
+    int nb_sns, i;
+    char buf[256];
+
+    /* find the target bs */
+    bs = bdrv_find(device);
+    if (!bs) {
+        monitor_printf(mon, "Device '%s' not found.\n", device);
+        return ;
+    }
+
+    if (!bdrv_can_snapshot(bs)) {
+        monitor_printf(mon, "Device '%s' can't have snapshot.\n", device);
+        return ;
+    }
+
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    if (nb_sns < 0) {
+        monitor_printf(mon, "Device %s bdrv_snapshot_list: error %d\n",
+                       device, nb_sns);
+        return;
+    }
+
+    if (nb_sns == 0) {
+        monitor_printf(mon, "There is no snapshot available.\n");
+        return;
+    }
+
+    monitor_printf(mon, "Device %s:\n", device);
+    monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+    for (i = 0; i < nb_sns; i++) {
+        sn = &sn_tab[i];
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+    }
+    g_free(sn_tab);
+    return;
+}
+
+void do_info_snapshots(Monitor *mon, const QDict *qdict)
+{
+    /* Todo, there should be a layer rebuild qdict before enter this func. */
+    const char *device = qdict_get_try_str(qdict, "params");
+    if (!device) {
+        do_info_snapshots_vm(mon);
+    } else {
+        do_info_snapshots_blk(mon, device);
+    }
+    return;
+}
+
 void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
 {
     qemu_ram_set_idstr(memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK,
diff --git a/sysemu.h b/sysemu.h
index 1b6add2..a1254bf 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -68,7 +68,7 @@ void qemu_add_machine_init_done_notifier(Notifier *notify);
 void do_savevm(Monitor *mon, const QDict *qdict);
 int load_vmstate(const char *name);
 void do_delvm(Monitor *mon, const QDict *qdict);
-void do_info_snapshots(Monitor *mon);
+void do_info_snapshots(Monitor *mon, const QDict *qdict);
 
 void qemu_announce_self(void);
 
-- 
1.7.1





reply via email to

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