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