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