]>
Commit | Line | Data |
---|---|---|
7378b84a DM |
1 | Index: new/qapi-schema.json |
2 | =================================================================== | |
3 | --- new.orig/qapi-schema.json 2012-09-04 12:52:21.000000000 +0200 | |
71788d62 DM |
4 | +++ new/qapi-schema.json 2012-09-06 11:26:26.000000000 +0200 |
5 | @@ -2493,3 +2493,12 @@ | |
7378b84a DM |
6 | # Since: 1.2.0 |
7 | ## | |
8 | { 'command': 'query-target', 'returns': 'TargetInfo' } | |
9 | + | |
10 | + | |
71788d62 | 11 | +{ 'command': 'snapshot-start' 'data': { '*statefile': 'str' } } |
7378b84a DM |
12 | + |
13 | +{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } } | |
14 | + | |
71788d62 DM |
15 | +{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } } |
16 | + | |
7378b84a DM |
17 | +{ 'command': 'snapshot-end' } |
18 | Index: new/qmp.c | |
19 | =================================================================== | |
20 | --- new.orig/qmp.c 2012-09-04 12:52:21.000000000 +0200 | |
71788d62 DM |
21 | +++ new/qmp.c 2012-09-06 11:28:14.000000000 +0200 |
22 | @@ -479,3 +479,191 @@ | |
7378b84a DM |
23 | return arch_query_cpu_definitions(errp); |
24 | } | |
25 | ||
26 | +static struct SnapshotState { | |
27 | + int in_progress; | |
28 | + int saved_vm_running; | |
29 | +} snap_state; | |
30 | + | |
71788d62 | 31 | +void qmp_snapshot_start(bool has_statefile, const char *statefile, Error **errp) |
7378b84a DM |
32 | +{ |
33 | + QEMUFile *f; | |
34 | + int ret; | |
35 | + | |
36 | + if (snap_state.in_progress) { | |
37 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
38 | + "VM snapshot already started\n"); | |
39 | + return; | |
40 | + } | |
e3a98889 | 41 | + |
7378b84a DM |
42 | + snap_state.in_progress = 1; |
43 | + | |
44 | + snap_state.saved_vm_running = runstate_is_running(); | |
45 | + | |
46 | + vm_stop(RUN_STATE_SAVE_VM); | |
47 | + | |
71788d62 DM |
48 | + if (!has_statefile) |
49 | + return; | |
50 | + | |
7378b84a DM |
51 | + f = qemu_fopen(statefile, "wb"); |
52 | + if (!f) { | |
53 | + error_set(errp, QERR_OPEN_FILE_FAILED, statefile); | |
e3a98889 | 54 | + goto restart; |
7378b84a DM |
55 | + } |
56 | + | |
e3a98889 | 57 | + ret = qemu_savevm_state(f); |
7378b84a DM |
58 | + qemu_fclose(f); |
59 | + if (ret < 0) { | |
60 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
61 | + "Error %d while writing VM state\n", ret); | |
e3a98889 DM |
62 | + goto restart; |
63 | + } | |
64 | + | |
65 | + return; | |
66 | + | |
67 | +restart: | |
68 | + | |
69 | + snap_state.in_progress = 0; | |
70 | + | |
71 | + if (snap_state.saved_vm_running) { | |
72 | + vm_start(); | |
7378b84a DM |
73 | + } |
74 | +} | |
75 | + | |
76 | +void qmp_snapshot_end(Error **errp) | |
77 | +{ | |
78 | + if (!snap_state.in_progress) { | |
79 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
80 | + "VM snapshot not started\n"); | |
81 | + return; | |
82 | + } | |
83 | + snap_state.in_progress = 0; | |
84 | + | |
85 | + if (snap_state.saved_vm_running) { | |
86 | + vm_start(); | |
87 | + } | |
88 | +} | |
89 | + | |
90 | +/* Fixme: Copied from savevm */ | |
91 | +static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, | |
92 | + const char *name) | |
93 | +{ | |
94 | + QEMUSnapshotInfo *sn_tab, *sn; | |
95 | + int nb_sns, i, ret; | |
96 | + | |
97 | + ret = -ENOENT; | |
98 | + nb_sns = bdrv_snapshot_list(bs, &sn_tab); | |
99 | + if (nb_sns < 0) | |
100 | + return ret; | |
101 | + for(i = 0; i < nb_sns; i++) { | |
102 | + sn = &sn_tab[i]; | |
103 | + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { | |
104 | + *sn_info = *sn; | |
105 | + ret = 0; | |
106 | + break; | |
107 | + } | |
108 | + } | |
109 | + g_free(sn_tab); | |
110 | + return ret; | |
111 | +} | |
112 | + | |
113 | +void qmp_snapshot_drive(const char *device, const char *name, Error **errp) | |
114 | +{ | |
115 | + BlockDriverState *bs; | |
116 | + QEMUSnapshotInfo sn1, *sn = &sn1; | |
117 | + int ret; | |
118 | +#ifdef _WIN32 | |
119 | + struct _timeb tb; | |
120 | +#else | |
121 | + struct timeval tv; | |
122 | +#endif | |
123 | + | |
124 | + if (!snap_state.in_progress) { | |
125 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
126 | + "VM snapshot not started\n"); | |
127 | + return; | |
128 | + } | |
129 | + | |
130 | + bs = bdrv_find(device); | |
131 | + if (!bs) { | |
132 | + error_set(errp, QERR_DEVICE_NOT_FOUND, device); | |
133 | + return; | |
134 | + } | |
135 | + | |
136 | + if (!bdrv_is_inserted(bs)) { | |
137 | + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); | |
138 | + return; | |
139 | + } | |
140 | + | |
141 | + if (bdrv_is_read_only(bs)) { | |
142 | + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device); | |
143 | + return; | |
144 | + } | |
145 | + | |
146 | + if (!bdrv_can_snapshot(bs)) { | |
147 | + error_set(errp, QERR_NOT_SUPPORTED); | |
148 | + return; | |
149 | + } | |
150 | + | |
151 | + if (bdrv_snapshot_find(bs, sn, name) >= 0) { | |
152 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
153 | + "snapshot '%s' already exists", name); | |
154 | + return; | |
155 | + } | |
156 | + | |
157 | + sn = &sn1; | |
158 | + memset(sn, 0, sizeof(*sn)); | |
159 | + | |
160 | +#ifdef _WIN32 | |
161 | + _ftime(&tb); | |
162 | + sn->date_sec = tb.time; | |
163 | + sn->date_nsec = tb.millitm * 1000000; | |
164 | +#else | |
165 | + gettimeofday(&tv, NULL); | |
166 | + sn->date_sec = tv.tv_sec; | |
167 | + sn->date_nsec = tv.tv_usec * 1000; | |
168 | +#endif | |
169 | + sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); | |
170 | + | |
171 | + pstrcpy(sn->name, sizeof(sn->name), name); | |
172 | + | |
173 | + sn->vm_state_size = 0; /* do not save state */ | |
174 | + | |
175 | + ret = bdrv_snapshot_create(bs, sn); | |
176 | + if (ret < 0) { | |
177 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while creating snapshot on '%s'\n", device); | |
178 | + return; | |
179 | + } | |
180 | +} | |
71788d62 DM |
181 | + |
182 | +void qmp_delete_drive_snapshot(const char *device, const char *name, Error **errp) | |
183 | +{ | |
184 | + BlockDriverState *bs; | |
185 | + QEMUSnapshotInfo sn1, *sn = &sn1; | |
186 | + int ret; | |
187 | + | |
188 | + bs = bdrv_find(device); | |
189 | + if (!bs) { | |
190 | + error_set(errp, QERR_DEVICE_NOT_FOUND, device); | |
191 | + return; | |
192 | + } | |
193 | + if (bdrv_is_read_only(bs)) { | |
194 | + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device); | |
195 | + return; | |
196 | + } | |
197 | + | |
198 | + if (!bdrv_can_snapshot(bs)) { | |
199 | + error_set(errp, QERR_NOT_SUPPORTED); | |
200 | + return; | |
201 | + } | |
202 | + | |
203 | + if (bdrv_snapshot_find(bs, sn, name) < 0) { | |
204 | + /* return success if snapshot does not exists */ | |
205 | + return; | |
206 | + } | |
207 | + | |
208 | + ret = bdrv_snapshot_delete(bs, name); | |
209 | + if (ret < 0) { | |
210 | + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while deleting snapshot on '%s'\n", device); | |
211 | + return; | |
212 | + } | |
213 | +} | |
7378b84a DM |
214 | Index: new/qmp-commands.hx |
215 | =================================================================== | |
216 | --- new.orig/qmp-commands.hx 2012-09-04 12:52:21.000000000 +0200 | |
71788d62 DM |
217 | +++ new/qmp-commands.hx 2012-09-06 11:13:10.000000000 +0200 |
218 | @@ -2514,3 +2514,27 @@ | |
7378b84a DM |
219 | .args_type = "", |
220 | .mhandler.cmd_new = qmp_marshal_input_query_target, | |
221 | }, | |
222 | + | |
223 | + { | |
224 | + .name = "snapshot-start", | |
225 | + .args_type = "statefile:s", | |
226 | + .mhandler.cmd_new = qmp_marshal_input_snapshot_start, | |
227 | + }, | |
228 | + | |
229 | + { | |
230 | + .name = "snapshot-drive", | |
231 | + .args_type = "device:s,name:s", | |
232 | + .mhandler.cmd_new = qmp_marshal_input_snapshot_drive, | |
233 | + }, | |
234 | + | |
235 | + { | |
71788d62 DM |
236 | + .name = "delete-drive-snapshot", |
237 | + .args_type = "device:s,name:s", | |
238 | + .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot, | |
239 | + }, | |
240 | + | |
241 | + { | |
7378b84a DM |
242 | + .name = "snapshot-end", |
243 | + .args_type = "", | |
244 | + .mhandler.cmd_new = qmp_marshal_input_snapshot_end, | |
245 | + }, | |
246 | Index: new/hmp.c | |
247 | =================================================================== | |
248 | --- new.orig/hmp.c 2012-09-04 12:52:21.000000000 +0200 | |
71788d62 DM |
249 | +++ new/hmp.c 2012-09-06 11:30:32.000000000 +0200 |
250 | @@ -1102,3 +1102,40 @@ | |
7378b84a DM |
251 | qmp_closefd(fdname, &errp); |
252 | hmp_handle_error(mon, &errp); | |
253 | } | |
254 | + | |
255 | +void hmp_snapshot_start(Monitor *mon, const QDict *qdict) | |
256 | +{ | |
257 | + Error *errp = NULL; | |
71788d62 | 258 | + const char *statefile = qdict_get_try_str(qdict, "statefile"); |
7378b84a | 259 | + |
71788d62 | 260 | + qmp_snapshot_start(statefile != NULL, statefile, &errp); |
7378b84a DM |
261 | + hmp_handle_error(mon, &errp); |
262 | +} | |
263 | + | |
264 | +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict) | |
265 | +{ | |
266 | + Error *errp = NULL; | |
267 | + const char *name = qdict_get_str(qdict, "name"); | |
268 | + const char *device = qdict_get_str(qdict, "device"); | |
269 | + | |
270 | + qmp_snapshot_drive(device, name, &errp); | |
271 | + hmp_handle_error(mon, &errp); | |
272 | +} | |
273 | + | |
71788d62 DM |
274 | +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict) |
275 | +{ | |
276 | + Error *errp = NULL; | |
277 | + const char *name = qdict_get_str(qdict, "name"); | |
278 | + const char *device = qdict_get_str(qdict, "device"); | |
279 | + | |
280 | + qmp_delete_drive_snapshot(device, name, &errp); | |
281 | + hmp_handle_error(mon, &errp); | |
282 | +} | |
283 | + | |
7378b84a DM |
284 | +void hmp_snapshot_end(Monitor *mon, const QDict *qdict) |
285 | +{ | |
286 | + Error *errp = NULL; | |
287 | + | |
288 | + qmp_snapshot_end(&errp); | |
289 | + hmp_handle_error(mon, &errp); | |
290 | +} | |
291 | Index: new/hmp.h | |
292 | =================================================================== | |
293 | --- new.orig/hmp.h 2012-09-04 12:52:21.000000000 +0200 | |
71788d62 DM |
294 | +++ new/hmp.h 2012-09-06 11:14:38.000000000 +0200 |
295 | @@ -71,5 +71,9 @@ | |
7378b84a DM |
296 | void hmp_netdev_del(Monitor *mon, const QDict *qdict); |
297 | void hmp_getfd(Monitor *mon, const QDict *qdict); | |
298 | void hmp_closefd(Monitor *mon, const QDict *qdict); | |
299 | +void hmp_snapshot_start(Monitor *mon, const QDict *qdict); | |
300 | +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict); | |
71788d62 | 301 | +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict); |
7378b84a DM |
302 | +void hmp_snapshot_end(Monitor *mon, const QDict *qdict); |
303 | ||
304 | #endif | |
305 | Index: new/hmp-commands.hx | |
306 | =================================================================== | |
307 | --- new.orig/hmp-commands.hx 2012-09-04 12:52:21.000000000 +0200 | |
71788d62 DM |
308 | +++ new/hmp-commands.hx 2012-09-06 11:29:05.000000000 +0200 |
309 | @@ -1494,3 +1494,35 @@ | |
7378b84a DM |
310 | STEXI |
311 | @end table | |
312 | ETEXI | |
313 | + | |
314 | + { | |
315 | + .name = "snapshot-start", | |
71788d62 DM |
316 | + .args_type = "statefile:s?", |
317 | + .params = "[statefile]", | |
7378b84a DM |
318 | + .help = "Prepare for snapshot and halt VM. Save VM state to statefile.", |
319 | + .mhandler.cmd = hmp_snapshot_start, | |
320 | + }, | |
321 | + | |
7378b84a DM |
322 | + { |
323 | + .name = "snapshot-drive", | |
324 | + .args_type = "device:s,name:s", | |
325 | + .params = "device name", | |
326 | + .help = "Create internal snapshot.", | |
327 | + .mhandler.cmd = hmp_snapshot_drive, | |
328 | + }, | |
329 | + | |
330 | + { | |
71788d62 DM |
331 | + .name = "delete-drive-snapshot", |
332 | + .args_type = "device:s,name:s", | |
333 | + .params = "device name", | |
334 | + .help = "Delete internal snapshot.", | |
335 | + .mhandler.cmd = hmp_delete_drive_snapshot, | |
336 | + }, | |
337 | + | |
338 | + { | |
7378b84a DM |
339 | + .name = "snapshot-end", |
340 | + .args_type = "", | |
341 | + .params = "", | |
342 | + .help = "Resume VM after snaphot.", | |
343 | + .mhandler.cmd = hmp_snapshot_end, | |
344 | + }, | |
e3a98889 DM |
345 | Index: new/savevm.c |
346 | =================================================================== | |
347 | --- new.orig/savevm.c 2012-09-05 10:27:37.000000000 +0200 | |
348 | +++ new/savevm.c 2012-09-05 10:27:44.000000000 +0200 | |
349 | @@ -1724,7 +1724,7 @@ | |
350 | } | |
351 | } | |
352 | ||
353 | -static int qemu_savevm_state(QEMUFile *f) | |
354 | +int qemu_savevm_state(QEMUFile *f) | |
355 | { | |
356 | int ret; | |
357 | MigrationParams params = { | |
358 | Index: new/sysemu.h | |
359 | =================================================================== | |
360 | --- new.orig/sysemu.h 2012-09-05 10:30:42.000000000 +0200 | |
361 | +++ new/sysemu.h 2012-09-05 10:30:58.000000000 +0200 | |
362 | @@ -83,6 +83,7 @@ | |
363 | int qemu_savevm_state_iterate(QEMUFile *f); | |
364 | int qemu_savevm_state_complete(QEMUFile *f); | |
365 | void qemu_savevm_state_cancel(QEMUFile *f); | |
366 | +int qemu_savevm_state(QEMUFile *f); | |
367 | int qemu_loadvm_state(QEMUFile *f); | |
368 | ||
369 | /* SLIRP */ |