]> git.proxmox.com Git - pve-qemu-kvm.git/blob - debian/patches/internal-snapshot.patch
snapshot_start: use bdrv instead of file
[pve-qemu-kvm.git] / debian / patches / internal-snapshot.patch
1 Index: new/qapi-schema.json
2 ===================================================================
3 --- new.orig/qapi-schema.json 2012-09-07 07:41:45.000000000 +0200
4 +++ new/qapi-schema.json 2012-09-13 09:22:06.000000000 +0200
5 @@ -2493,3 +2493,12 @@
6 # Since: 1.2.0
7 ##
8 { 'command': 'query-target', 'returns': 'TargetInfo' }
9 +
10 +
11 +{ 'command': 'snapshot-start' 'data': { '*statefile': 'str' } }
12 +
13 +{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
14 +
15 +{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
16 +
17 +{ 'command': 'snapshot-end' }
18 Index: new/qmp.c
19 ===================================================================
20 --- new.orig/qmp.c 2012-09-07 07:41:45.000000000 +0200
21 +++ new/qmp.c 2012-09-14 14:06:56.000000000 +0200
22 @@ -479,3 +479,224 @@
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 +
31 +static int block_put_buffer(void *opaque, const uint8_t *buf,
32 + int64_t pos, int size)
33 +{
34 + bdrv_pwrite(opaque, pos, buf, size);
35 + return size;
36 +}
37 +
38 +static int bdrv_fclose(void *opaque)
39 +{
40 + return bdrv_flush(opaque);
41 +}
42 +
43 +void qmp_snapshot_start(bool has_statefile, const char *statefile, Error **errp)
44 +{
45 + BlockDriverState *bs = NULL;
46 + BlockDriver *drv = NULL;
47 + int bdrv_oflags = BDRV_O_NOCACHE | BDRV_O_RDWR;
48 + QEMUFile *f;
49 + int ret;
50 +
51 + if (snap_state.in_progress) {
52 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
53 + "VM snapshot already started\n");
54 + return;
55 + }
56 +
57 + snap_state.in_progress = 1;
58 +
59 + snap_state.saved_vm_running = runstate_is_running();
60 +
61 + vm_stop(RUN_STATE_SAVE_VM);
62 +
63 + if (!has_statefile)
64 + return;
65 +
66 + /* Open the image */
67 + bs = bdrv_new("vmstate");
68 + ret = bdrv_open(bs, statefile, bdrv_oflags, drv);
69 + if (ret < 0) {
70 + error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
71 + goto restart;
72 + }
73 +
74 + f = qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
75 + NULL, NULL, NULL);
76 + if (!f) {
77 + error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
78 + goto restart;
79 + }
80 +
81 + ret = qemu_savevm_state(f);
82 +
83 + bdrv_truncate(bs, qemu_ftell(f)); // ignore errors
84 +
85 + qemu_fclose(f);
86 +
87 + if (ret < 0) {
88 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
89 + "Error %d while writing VM state\n", ret);
90 + goto restart;
91 + }
92 +end:
93 + if (bs)
94 + bdrv_delete(bs);
95 +
96 + return;
97 +
98 +restart:
99 +
100 + snap_state.in_progress = 0;
101 +
102 + if (snap_state.saved_vm_running) {
103 + vm_start();
104 + }
105 +
106 + goto end;
107 +}
108 +
109 +void qmp_snapshot_end(Error **errp)
110 +{
111 + if (!snap_state.in_progress) {
112 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
113 + "VM snapshot not started\n");
114 + return;
115 + }
116 + snap_state.in_progress = 0;
117 +
118 + if (snap_state.saved_vm_running) {
119 + vm_start();
120 + }
121 +}
122 +
123 +/* Fixme: Copied from savevm */
124 +static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
125 + const char *name)
126 +{
127 + QEMUSnapshotInfo *sn_tab, *sn;
128 + int nb_sns, i, ret;
129 +
130 + ret = -ENOENT;
131 + nb_sns = bdrv_snapshot_list(bs, &sn_tab);
132 + if (nb_sns < 0)
133 + return ret;
134 + for(i = 0; i < nb_sns; i++) {
135 + sn = &sn_tab[i];
136 + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
137 + *sn_info = *sn;
138 + ret = 0;
139 + break;
140 + }
141 + }
142 + g_free(sn_tab);
143 + return ret;
144 +}
145 +
146 +void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
147 +{
148 + BlockDriverState *bs;
149 + QEMUSnapshotInfo sn1, *sn = &sn1;
150 + int ret;
151 +#ifdef _WIN32
152 + struct _timeb tb;
153 +#else
154 + struct timeval tv;
155 +#endif
156 +
157 + if (!snap_state.in_progress) {
158 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
159 + "VM snapshot not started\n");
160 + return;
161 + }
162 +
163 + bs = bdrv_find(device);
164 + if (!bs) {
165 + error_set(errp, QERR_DEVICE_NOT_FOUND, device);
166 + return;
167 + }
168 +
169 + if (!bdrv_is_inserted(bs)) {
170 + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
171 + return;
172 + }
173 +
174 + if (bdrv_is_read_only(bs)) {
175 + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
176 + return;
177 + }
178 +
179 + if (!bdrv_can_snapshot(bs)) {
180 + error_set(errp, QERR_NOT_SUPPORTED);
181 + return;
182 + }
183 +
184 + if (bdrv_snapshot_find(bs, sn, name) >= 0) {
185 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
186 + "snapshot '%s' already exists", name);
187 + return;
188 + }
189 +
190 + sn = &sn1;
191 + memset(sn, 0, sizeof(*sn));
192 +
193 +#ifdef _WIN32
194 + _ftime(&tb);
195 + sn->date_sec = tb.time;
196 + sn->date_nsec = tb.millitm * 1000000;
197 +#else
198 + gettimeofday(&tv, NULL);
199 + sn->date_sec = tv.tv_sec;
200 + sn->date_nsec = tv.tv_usec * 1000;
201 +#endif
202 + sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
203 +
204 + pstrcpy(sn->name, sizeof(sn->name), name);
205 +
206 + sn->vm_state_size = 0; /* do not save state */
207 +
208 + ret = bdrv_snapshot_create(bs, sn);
209 + if (ret < 0) {
210 + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while creating snapshot on '%s'\n", device);
211 + return;
212 + }
213 +}
214 +
215 +void qmp_delete_drive_snapshot(const char *device, const char *name, Error **errp)
216 +{
217 + BlockDriverState *bs;
218 + QEMUSnapshotInfo sn1, *sn = &sn1;
219 + int ret;
220 +
221 + bs = bdrv_find(device);
222 + if (!bs) {
223 + error_set(errp, QERR_DEVICE_NOT_FOUND, device);
224 + return;
225 + }
226 + if (bdrv_is_read_only(bs)) {
227 + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
228 + return;
229 + }
230 +
231 + if (!bdrv_can_snapshot(bs)) {
232 + error_set(errp, QERR_NOT_SUPPORTED);
233 + return;
234 + }
235 +
236 + if (bdrv_snapshot_find(bs, sn, name) < 0) {
237 + /* return success if snapshot does not exists */
238 + return;
239 + }
240 +
241 + ret = bdrv_snapshot_delete(bs, name);
242 + if (ret < 0) {
243 + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while deleting snapshot on '%s'\n", device);
244 + return;
245 + }
246 +}
247 Index: new/qmp-commands.hx
248 ===================================================================
249 --- new.orig/qmp-commands.hx 2012-09-07 07:41:45.000000000 +0200
250 +++ new/qmp-commands.hx 2012-09-13 09:30:33.000000000 +0200
251 @@ -2514,3 +2514,27 @@
252 .args_type = "",
253 .mhandler.cmd_new = qmp_marshal_input_query_target,
254 },
255 +
256 + {
257 + .name = "snapshot-start",
258 + .args_type = "statefile:s?",
259 + .mhandler.cmd_new = qmp_marshal_input_snapshot_start,
260 + },
261 +
262 + {
263 + .name = "snapshot-drive",
264 + .args_type = "device:s,name:s",
265 + .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
266 + },
267 +
268 + {
269 + .name = "delete-drive-snapshot",
270 + .args_type = "device:s,name:s",
271 + .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
272 + },
273 +
274 + {
275 + .name = "snapshot-end",
276 + .args_type = "",
277 + .mhandler.cmd_new = qmp_marshal_input_snapshot_end,
278 + },
279 Index: new/hmp.c
280 ===================================================================
281 --- new.orig/hmp.c 2012-09-07 07:41:45.000000000 +0200
282 +++ new/hmp.c 2012-09-13 09:22:06.000000000 +0200
283 @@ -1102,3 +1102,40 @@
284 qmp_closefd(fdname, &errp);
285 hmp_handle_error(mon, &errp);
286 }
287 +
288 +void hmp_snapshot_start(Monitor *mon, const QDict *qdict)
289 +{
290 + Error *errp = NULL;
291 + const char *statefile = qdict_get_try_str(qdict, "statefile");
292 +
293 + qmp_snapshot_start(statefile != NULL, statefile, &errp);
294 + hmp_handle_error(mon, &errp);
295 +}
296 +
297 +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
298 +{
299 + Error *errp = NULL;
300 + const char *name = qdict_get_str(qdict, "name");
301 + const char *device = qdict_get_str(qdict, "device");
302 +
303 + qmp_snapshot_drive(device, name, &errp);
304 + hmp_handle_error(mon, &errp);
305 +}
306 +
307 +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict)
308 +{
309 + Error *errp = NULL;
310 + const char *name = qdict_get_str(qdict, "name");
311 + const char *device = qdict_get_str(qdict, "device");
312 +
313 + qmp_delete_drive_snapshot(device, name, &errp);
314 + hmp_handle_error(mon, &errp);
315 +}
316 +
317 +void hmp_snapshot_end(Monitor *mon, const QDict *qdict)
318 +{
319 + Error *errp = NULL;
320 +
321 + qmp_snapshot_end(&errp);
322 + hmp_handle_error(mon, &errp);
323 +}
324 Index: new/hmp.h
325 ===================================================================
326 --- new.orig/hmp.h 2012-09-07 07:41:45.000000000 +0200
327 +++ new/hmp.h 2012-09-13 09:22:06.000000000 +0200
328 @@ -71,5 +71,9 @@
329 void hmp_netdev_del(Monitor *mon, const QDict *qdict);
330 void hmp_getfd(Monitor *mon, const QDict *qdict);
331 void hmp_closefd(Monitor *mon, const QDict *qdict);
332 +void hmp_snapshot_start(Monitor *mon, const QDict *qdict);
333 +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
334 +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
335 +void hmp_snapshot_end(Monitor *mon, const QDict *qdict);
336
337 #endif
338 Index: new/hmp-commands.hx
339 ===================================================================
340 --- new.orig/hmp-commands.hx 2012-09-07 07:41:45.000000000 +0200
341 +++ new/hmp-commands.hx 2012-09-13 09:22:06.000000000 +0200
342 @@ -1494,3 +1494,35 @@
343 STEXI
344 @end table
345 ETEXI
346 +
347 + {
348 + .name = "snapshot-start",
349 + .args_type = "statefile:s?",
350 + .params = "[statefile]",
351 + .help = "Prepare for snapshot and halt VM. Save VM state to statefile.",
352 + .mhandler.cmd = hmp_snapshot_start,
353 + },
354 +
355 + {
356 + .name = "snapshot-drive",
357 + .args_type = "device:s,name:s",
358 + .params = "device name",
359 + .help = "Create internal snapshot.",
360 + .mhandler.cmd = hmp_snapshot_drive,
361 + },
362 +
363 + {
364 + .name = "delete-drive-snapshot",
365 + .args_type = "device:s,name:s",
366 + .params = "device name",
367 + .help = "Delete internal snapshot.",
368 + .mhandler.cmd = hmp_delete_drive_snapshot,
369 + },
370 +
371 + {
372 + .name = "snapshot-end",
373 + .args_type = "",
374 + .params = "",
375 + .help = "Resume VM after snaphot.",
376 + .mhandler.cmd = hmp_snapshot_end,
377 + },
378 Index: new/savevm.c
379 ===================================================================
380 --- new.orig/savevm.c 2012-09-07 07:41:45.000000000 +0200
381 +++ new/savevm.c 2012-09-14 11:32:17.000000000 +0200
382 @@ -404,7 +404,7 @@
383 return bdrv_flush(opaque);
384 }
385
386 -static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
387 +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
388 {
389 if (is_writable)
390 return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
391 @@ -1724,7 +1724,7 @@
392 }
393 }
394
395 -static int qemu_savevm_state(QEMUFile *f)
396 +int qemu_savevm_state(QEMUFile *f)
397 {
398 int ret;
399 MigrationParams params = {
400 Index: new/sysemu.h
401 ===================================================================
402 --- new.orig/sysemu.h 2012-09-07 07:41:46.000000000 +0200
403 +++ new/sysemu.h 2012-09-13 09:22:06.000000000 +0200
404 @@ -83,6 +83,7 @@
405 int qemu_savevm_state_iterate(QEMUFile *f);
406 int qemu_savevm_state_complete(QEMUFile *f);
407 void qemu_savevm_state_cancel(QEMUFile *f);
408 +int qemu_savevm_state(QEMUFile *f);
409 int qemu_loadvm_state(QEMUFile *f);
410
411 /* SLIRP */
412 Index: new/qemu-file.h
413 ===================================================================
414 --- new.orig/qemu-file.h 2012-09-14 11:51:31.000000000 +0200
415 +++ new/qemu-file.h 2012-09-14 11:51:47.000000000 +0200
416 @@ -68,6 +68,7 @@
417 QEMUFile *qemu_fopen(const char *filename, const char *mode);
418 QEMUFile *qemu_fdopen(int fd, const char *mode);
419 QEMUFile *qemu_fopen_socket(int fd);
420 +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable);
421 QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
422 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
423 int qemu_stdio_fd(QEMUFile *f);