@@ -553,6 +553,40 @@ void hmp_info_block_jobs(Monitor *mon)
}
}
+void hmp_info_snapshots(Monitor *mon)
+{
+ SnapshotInfoList *list;
+ Error *err = NULL;
+ char buf[256];
+ QEMUSnapshotInfo sn;
+
+ list = qmp_query_snapshots(&err);
+
+ if (error_is_set(&err)) {
+ hmp_handle_error(mon, &err);
+ return;
+ }
+
+ if (!list) {
+ monitor_printf(mon, "There is no snapshot available.\n");
+ return;
+ }
+
+ monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+ while (list) {
+ memcpy(&(sn.id_str), list->value->id, sizeof(sn.id_str));
+ memcpy(&(sn.name), list->value->tag, sizeof(sn.name));
+ sn.date_sec = list->value->date;
+ sn.date_nsec = sn.date_nsec * 1000;
+ sn.vm_clock_nsec = list->value->vm_clock;
+ sn.vm_state_size = list->value->vm_size;
+ monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
+ list = list->next;
+ }
+
+ qapi_free_SnapshotInfoList(list);
+}
+
void hmp_quit(Monitor *mon, const QDict *qdict)
{
monitor_suspend(mon);
@@ -33,6 +33,7 @@ void hmp_info_spice(Monitor *mon);
void hmp_info_balloon(Monitor *mon);
void hmp_info_pci(Monitor *mon);
void hmp_info_block_jobs(Monitor *mon);
+void hmp_info_snapshots(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
@@ -2596,7 +2596,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the currently saved VM snapshots",
- .mhandler.info = do_info_snapshots,
+ .mhandler.info = hmp_info_snapshots,
},
{
.name = "status",
@@ -934,6 +934,41 @@
{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
##
+# @SnapshotInfo:
+#
+# Snapshot list. This structure contains list of snapshots for virtual machine.
+#
+# @id: id of the snapshot.
+#
+# @tag: human readable tag of the snapshot.
+#
+# @vm_size: size of the snapshot in Bytes.
+#
+# @date: date and time of the snapshot as timestamp.
+#
+# @vm_clock: time in the guest in nsecs.
+#
+# Since: 1.2
+##
+{ 'type': 'SnapshotInfo',
+ 'data': {'id': 'str', 'tag': 'str', 'vm_size': 'int',
+ 'date': 'int', 'vm_clock': 'int'} }
+
+##
+# @query-snapshots:
+#
+# List available snapshots for VM.
+#
+# Returns: a list of @SnapshotInfo describing each snapshot or an empty list
+# on success
+# If no block device can accept snapshots, SnapshotNotAccepted
+# If loading snapshot list failed, SnapshotListFailed
+#
+# Since: 1.2
+##
+{ 'command': 'query-snapshots', 'returns': ['SnapshotInfo'] }
+
+##
# @quit:
#
# This command will cause the QEMU process to exit gracefully. While every
@@ -325,6 +325,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' disk-only snapshot. Revert to it offline using qemu-img.",
},
{
+ .error_fmt = QERR_SNAPSHOT_LIST_FAILED,
+ .desc = "Error '%(errno)' while listing snapshots on '%(device)'",
+ },
+ {
.error_fmt = QERR_SNAPSHOT_LOAD_FAILED,
.desc = "Error '%(errno)' while loading snapshot for '%(device)'",
},
@@ -263,6 +263,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_SNAPSHOT_INVALID \
"{ 'class': 'SnapshotInvalid', 'data': { 'device': %s } }"
+#define QERR_SNAPSHOT_LIST_FAILED \
+ "{ 'class': 'SnapshotListFailed', 'data': { 'device': %s, 'errno': %d } }"
+
#define QERR_SNAPSHOT_LOAD_FAILED \
"{ 'class': 'SnapshotLoadFailed', 'data': { 'device': %s, 'errno': %d } }"
@@ -2284,3 +2284,34 @@ EQMP
.args_type = "implements:s?,abstract:b?",
.mhandler.cmd_new = qmp_marshal_input_qom_list_types,
},
+
+SQMP
+query-snapshots
+----------
+
+List available snapshots for VM.
+
+Return a json-object with the following information:
+
+- "id": id of the snapshot.
+
+- "tag": human readable tag of the snapshot.
+
+- "vm_size": size of the snapshot in Bytes.
+
+- "date": date and time of the snapshot as timestamp.
+
+- "vm_clock": time in the guest in nsecs.
+
+Example:
+
+-> { "execute": "query-snapshots" }
+<- {"return": [{"vm_size": 212309067, "tag": "my_snapshot",
+ "vm_clock": 630176706190, "id": "1", "date": 1341999856}]}
+
+EQMP
+ {
+ .name = "query-snapshots",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_snapshots,
+ },
@@ -2316,34 +2316,26 @@ void qmp_delvm(const char *name, Error **errp)
}
}
-void do_info_snapshots(Monitor *mon)
+SnapshotInfoList *qmp_query_snapshots(Error **errp)
{
+ SnapshotInfoList *snapshot_list = NULL, *last = NULL;
BlockDriverState *bs, *bs1;
QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
int nb_sns, i, ret, available;
- int total;
- int *available_snapshots;
- char buf[256];
bs = bdrv_snapshots();
if (!bs) {
- monitor_printf(mon, "No available block device supports snapshots\n");
- return;
+ error_set(errp, QERR_SNAPSHOT_NOT_ACCEPTED);
+ return NULL;
}
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
if (nb_sns < 0) {
- monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
- return;
- }
-
- if (nb_sns == 0) {
- monitor_printf(mon, "There is no snapshot available.\n");
- return;
+ error_set(errp, QERR_SNAPSHOT_LIST_FAILED,
+ bdrv_get_device_name(bs), nb_sns);
+ return NULL;
}
- available_snapshots = g_malloc0(sizeof(int) * nb_sns);
- total = 0;
for (i = 0; i < nb_sns; i++) {
sn = &sn_tab[i];
available = 1;
@@ -2360,23 +2352,27 @@ void do_info_snapshots(Monitor *mon)
}
if (available) {
- available_snapshots[total] = i;
- total++;
- }
- }
-
- if (total > 0) {
- monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
- for (i = 0; i < total; i++) {
- sn = &sn_tab[available_snapshots[i]];
- monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+ SnapshotInfoList *info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->id = g_strdup(sn->id_str);
+ info->value->tag = g_strdup(sn->name);
+ info->value->vm_size = sn->vm_state_size;
+ info->value->date = sn->date_sec;
+ info->value->vm_clock = sn->vm_clock_nsec;
+
+ if (!snapshot_list) {
+ snapshot_list = info;
+ last = info;
+ } else {
+ last->next = info;
+ last = info;
+ }
}
- } else {
- monitor_printf(mon, "There is no suitable snapshot available\n");
}
g_free(sn_tab);
- g_free(available_snapshots);
+
+ return snapshot_list;
}
@@ -69,8 +69,6 @@ void qemu_remove_exit_notifier(Notifier *notify);
void qemu_add_machine_init_done_notifier(Notifier *notify);
-void do_info_snapshots(Monitor *mon);
-
void qemu_announce_self(void);
bool qemu_savevm_state_blocked(Error **errp);
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- hmp.c | 34 ++++++++++++++++++++++++++++++++++ hmp.h | 1 + monitor.c | 2 +- qapi-schema.json | 35 +++++++++++++++++++++++++++++++++++ qerror.c | 4 ++++ qerror.h | 3 +++ qmp-commands.hx | 31 +++++++++++++++++++++++++++++++ savevm.c | 52 ++++++++++++++++++++++++---------------------------- sysemu.h | 2 -- 9 files changed, 133 insertions(+), 31 deletions(-)