1From fdfc6b5ac98f4dca2590b3b301071b56e208421b Mon Sep 17 00:00:00 2001
2From: Pavel Balaev <mail@void.so>
3Date: Tue, 22 Jan 2019 19:00:32 +0300
4Subject: [PATCH] qmp: add {save|load|del}vm commands
5
6Signed-off-by: Pavel Balaev <mail@void.so>
7---
8 hmp.c              | 22 ++++++++-----------
9 migration/savevm.c | 27 +++++++++++++++++++++++
10 qapi/misc.json     | 54 ++++++++++++++++++++++++++++++++++++++++++++++
11 target/i386/kvm.c  |  6 +++---
12 4 files changed, 93 insertions(+), 16 deletions(-)
13
14diff --git a/hmp.c b/hmp.c
15index 7828f93a..2c3b67c1 100644
16--- a/hmp.c
17+++ b/hmp.c
18@@ -1377,37 +1377,33 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
19
20 void hmp_loadvm(Monitor *mon, const QDict *qdict)
21 {
22-    int saved_vm_running  = runstate_is_running();
23     const char *name = qdict_get_str(qdict, "name");
24     Error *err = NULL;
25
26-    vm_stop(RUN_STATE_RESTORE_VM);
27-
28-    if (load_snapshot(name, &err) == 0 && saved_vm_running) {
29-        vm_start();
30-    }
31+    qmp_loadvm(name, &err);
32     hmp_handle_error(mon, &err);
33 }
34
35 void hmp_savevm(Monitor *mon, const QDict *qdict)
36 {
37     Error *err = NULL;
38+    bool has_name = TRUE;
39+    const char *name = qdict_get_try_str(qdict, "name");
40
41-    save_snapshot(qdict_get_try_str(qdict, "name"), &err);
42+    if (name == NULL) {
43+        has_name = FALSE;
44+    }
45+
46+    qmp_savevm(has_name, name, &err);
47     hmp_handle_error(mon, &err);
48 }
49
50 void hmp_delvm(Monitor *mon, const QDict *qdict)
51 {
52-    BlockDriverState *bs;
53     Error *err = NULL;
54     const char *name = qdict_get_str(qdict, "name");
55
56-    if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
57-        error_reportf_err(err,
58-                          "Error while deleting snapshot on device '%s': ",
59-                          bdrv_get_device_name(bs));
60-    }
61+    qmp_delvm(name, &err);
62 }
63
64 void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
65diff --git a/migration/savevm.c b/migration/savevm.c
66index 9e45fb4f..6f505469 100644
67--- a/migration/savevm.c
68+++ b/migration/savevm.c
69@@ -2567,6 +2567,33 @@ int save_snapshot(const char *name, Error **errp)
70     return ret;
71 }
72
73+void qmp_savevm(bool has_name, const char *name, Error **errp)
74+{
75+    save_snapshot(has_name ? name : NULL, errp);
76+}
77+
78+void qmp_loadvm(const char *name, Error **errp)
79+{
80+    int saved_vm_running  = runstate_is_running();
81+
82+    vm_stop(RUN_STATE_RESTORE_VM);
83+
84+    if (load_snapshot(name, errp) == 0 && saved_vm_running) {
85+        vm_start();
86+    }
87+}
88+
89+void qmp_delvm(const char *name, Error **errp)
90+{
91+    BlockDriverState *bs;
92+
93+    if (bdrv_all_delete_snapshot(name, &bs, errp) < 0) {
94+        error_reportf_err(*errp,
95+                          "Error while deleting snapshot on device '%s': ",
96+                          bdrv_get_device_name(bs));
97+    }
98+}
99+
100 void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live,
101                                 Error **errp)
102 {
103diff --git a/qapi/misc.json b/qapi/misc.json
104index 6c1c5c0a..088eba8c 100644
105--- a/qapi/misc.json
106+++ b/qapi/misc.json
107@@ -3105,6 +3105,60 @@
108 { 'enum': 'ReplayMode',
109   'data': [ 'none', 'record', 'play' ] }
110
111+##
112+# @savevm:
113+#
114+# Save a VM snapshot. Without a name new snapshot is created.
115+#
116+# @name: identifier of a snapshot to be saved
117+#
118+# Returns: Nothing on success
119+#
120+# Since: 2.10
121+#
122+# Example:
123+#
124+# -> { "execute": "savevm", "arguments": { "name": "snapshot1" } }
125+# <- { "return": {} }
126+##
127+{ 'command': 'savevm', 'data': {'*name': 'str'} }
128+
129+##
130+# @loadvm:
131+#
132+# Load a VM snapshot.
133+#
134+# @name: identifier of a snapshot to be loaded
135+#
136+# Returns: Nothing on success
137+#
138+# Since: 2.10
139+#
140+# Example:
141+#
142+# -> { "execute": "loadvm", "arguments": { "name": "snapshot1" } }
143+# <- { "return": {} }
144+##
145+{ 'command': 'loadvm', 'data': {'name': 'str'} }
146+
147+##
148+# @delvm:
149+#
150+# Delete a VM snapshot.
151+#
152+# @name: identifier of a snapshot to be deleted
153+#
154+# Returns: Nothing on success
155+#
156+# Since: 2.10
157+#
158+# Example:
159+#
160+# -> { "execute": "delvm", "arguments": { "name": "snapshot1" } }
161+# <- { "return": {} }
162+##
163+{ 'command': 'delvm', 'data': {'name': 'str'} }
164+
165 ##
166 # @xen-load-devices-state:
167 #
168diff --git a/target/i386/kvm.c b/target/i386/kvm.c
169index b2401d13..8b724ebe 100644
170--- a/target/i386/kvm.c
171+++ b/target/i386/kvm.c
172@@ -855,7 +855,7 @@ static int hyperv_init_vcpu(X86CPU *cpu)
173 }
174
175 static Error *invtsc_mig_blocker;
176-static Error *vmx_mig_blocker;
177+/* static Error *vmx_mig_blocker; */
178
179 #define KVM_MAX_CPUID_ENTRIES  100
180
181@@ -1247,7 +1247,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
182         has_msr_feature_control = !!(c->ecx & CPUID_EXT_VMX) ||
183                                   !!(c->ecx & CPUID_EXT_SMX);
184     }
185-
186+#if 0
187     if ((env->features[FEAT_1_ECX] & CPUID_EXT_VMX) && !vmx_mig_blocker) {
188         error_setg(&vmx_mig_blocker,
189                    "Nested VMX virtualization does not support live migration yet");
190@@ -1258,7 +1258,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
191             return r;
192         }
193     }
194-
195+#endif
196     if (env->mcg_cap & MCG_LMCE_P) {
197         has_msr_mcg_ext_ctl = has_msr_feature_control = true;
198     }
199--
2002.19.2
201
202