1 /*
2 * qemu_snapshot.c: snapshot related implementation
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include "qemu_snapshot.h"
22
23 #include "qemu_monitor.h"
24 #include "qemu_domain.h"
25 #include "qemu_block.h"
26 #include "qemu_process.h"
27 #include "qemu_migration.h"
28 #include "qemu_command.h"
29 #include "qemu_security.h"
30 #include "qemu_saveimage.h"
31
32 #include "virerror.h"
33 #include "virlog.h"
34 #include "datatypes.h"
35 #include "viralloc.h"
36 #include "domain_conf.h"
37 #include "domain_audit.h"
38 #include "locking/domain_lock.h"
39 #include "libvirt_internal.h"
40 #include "virxml.h"
41 #include "virstoragefile.h"
42 #include "virstring.h"
43 #include "virdomainsnapshotobjlist.h"
44 #include "virqemu.h"
45 #include "storage_source.h"
46
47 #define VIR_FROM_THIS VIR_FROM_QEMU
48
49 VIR_LOG_INIT("qemu.qemu_snapshot");
50
51
52 /**
53 * qemuSnapshotSetCurrent: Set currently active snapshot
54 *
55 * @vm: domain object
56 * @newcurrent: snapshot object to set as current/active
57 *
58 * Sets @newcurrent as the 'current' snapshot of @vm. This helper ensures that
59 * the snapshot which was 'current' previously is updated.
60 */
61 static void
qemuSnapshotSetCurrent(virDomainObj * vm,virDomainMomentObj * newcurrent)62 qemuSnapshotSetCurrent(virDomainObj *vm,
63 virDomainMomentObj *newcurrent)
64 {
65 qemuDomainObjPrivate *priv = vm->privateData;
66 virQEMUDriver *driver = priv->driver;
67 g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
68 virDomainMomentObj *oldcurrent = virDomainSnapshotGetCurrent(vm->snapshots);
69
70 virDomainSnapshotSetCurrent(vm->snapshots, newcurrent);
71
72 /* we need to write out metadata for the old snapshot to update the
73 * 'active' property */
74 if (oldcurrent &&
75 oldcurrent != newcurrent) {
76 if (qemuDomainSnapshotWriteMetadata(vm, oldcurrent, driver->xmlopt, cfg->snapshotDir) < 0)
77 VIR_WARN("failed to update old current snapshot");
78 }
79 }
80
81
82 /* Looks up snapshot object from VM and name */
83 virDomainMomentObj *
qemuSnapObjFromName(virDomainObj * vm,const char * name)84 qemuSnapObjFromName(virDomainObj *vm,
85 const char *name)
86 {
87 virDomainMomentObj *snap = NULL;
88 snap = virDomainSnapshotFindByName(vm->snapshots, name);
89 if (!snap)
90 virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
91 _("no domain snapshot with matching name '%s'"),
92 name);
93
94 return snap;
95 }
96
97
98 /* Looks up snapshot object from VM and snapshotPtr */
99 virDomainMomentObj *
qemuSnapObjFromSnapshot(virDomainObj * vm,virDomainSnapshotPtr snapshot)100 qemuSnapObjFromSnapshot(virDomainObj *vm,
101 virDomainSnapshotPtr snapshot)
102 {
103 return qemuSnapObjFromName(vm, snapshot->name);
104 }
105
106
107 /* Count how many snapshots in a set are external snapshots. */
108 static int
qemuSnapshotCountExternal(void * payload,const char * name G_GNUC_UNUSED,void * data)109 qemuSnapshotCountExternal(void *payload,
110 const char *name G_GNUC_UNUSED,
111 void *data)
112 {
113 virDomainMomentObj *snap = payload;
114 int *count = data;
115
116 if (virDomainSnapshotIsExternal(snap))
117 (*count)++;
118 return 0;
119 }
120
121
122 int
qemuSnapshotFSFreeze(virDomainObj * vm,const char ** mountpoints,unsigned int nmountpoints)123 qemuSnapshotFSFreeze(virDomainObj *vm,
124 const char **mountpoints,
125 unsigned int nmountpoints)
126 {
127 qemuAgent *agent;
128 int frozen;
129
130 if (!qemuDomainAgentAvailable(vm, true))
131 return -1;
132
133 agent = qemuDomainObjEnterAgent(vm);
134 frozen = qemuAgentFSFreeze(agent, mountpoints, nmountpoints);
135 qemuDomainObjExitAgent(vm, agent);
136 return frozen;
137 }
138
139
140 /* Return -1 on error, otherwise number of thawed filesystems. */
141 int
qemuSnapshotFSThaw(virDomainObj * vm,bool report)142 qemuSnapshotFSThaw(virDomainObj *vm,
143 bool report)
144 {
145 qemuAgent *agent;
146 int thawed;
147 virErrorPtr err = NULL;
148
149 if (!qemuDomainAgentAvailable(vm, report))
150 return -1;
151
152 agent = qemuDomainObjEnterAgent(vm);
153 if (!report)
154 virErrorPreserveLast(&err);
155 thawed = qemuAgentFSThaw(agent);
156 qemuDomainObjExitAgent(vm, agent);
157
158 virErrorRestore(&err);
159
160 return thawed;
161 }
162
163
164 /* The domain is expected to be locked and inactive. */
165 static int
qemuSnapshotCreateInactiveInternal(virQEMUDriver * driver,virDomainObj * vm,virDomainMomentObj * snap)166 qemuSnapshotCreateInactiveInternal(virQEMUDriver *driver,
167 virDomainObj *vm,
168 virDomainMomentObj *snap)
169 {
170 return qemuDomainSnapshotForEachQcow2(driver, vm->def, snap, "-c", false);
171 }
172
173
174 /* The domain is expected to be locked and inactive. */
175 static int
qemuSnapshotCreateInactiveExternal(virQEMUDriver * driver,virDomainObj * vm,virDomainMomentObj * snap,bool reuse)176 qemuSnapshotCreateInactiveExternal(virQEMUDriver *driver,
177 virDomainObj *vm,
178 virDomainMomentObj *snap,
179 bool reuse)
180 {
181 size_t i;
182 virDomainSnapshotDiskDef *snapdisk;
183 virDomainDiskDef *defdisk;
184 virCommand *cmd = NULL;
185 const char *qemuImgPath;
186 virBitmap *created = NULL;
187 g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
188 int ret = -1;
189 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
190 virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(snap);
191
192 if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
193 goto cleanup;
194
195 created = virBitmapNew(snapdef->ndisks);
196
197 /* If reuse is true, then qemuSnapshotPrepare already
198 * ensured that the new files exist, and it was up to the user to
199 * create them correctly. */
200 for (i = 0; i < snapdef->ndisks && !reuse; i++) {
201 snapdisk = &(snapdef->disks[i]);
202 defdisk = vm->def->disks[i];
203 if (snapdisk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
204 continue;
205
206 if (!snapdisk->src->format)
207 snapdisk->src->format = VIR_STORAGE_FILE_QCOW2;
208
209 if (qemuDomainStorageSourceValidateDepth(defdisk->src, 1, defdisk->dst) < 0)
210 goto cleanup;
211
212 /* creates cmd line args: qemu-img create -f qcow2 -o */
213 if (!(cmd = virCommandNewArgList(qemuImgPath,
214 "create",
215 "-f",
216 virStorageFileFormatTypeToString(snapdisk->src->format),
217 "-o",
218 NULL)))
219 goto cleanup;
220
221 /* adds cmd line arg: backing_fmt=format,backing_file=/path/to/backing/file */
222 virBufferAsprintf(&buf, "backing_fmt=%s,backing_file=",
223 virStorageFileFormatTypeToString(defdisk->src->format));
224 virQEMUBuildBufferEscapeComma(&buf, defdisk->src->path);
225 virCommandAddArgBuffer(cmd, &buf);
226
227 /* adds cmd line args: /path/to/target/file */
228 virQEMUBuildBufferEscapeComma(&buf, snapdisk->src->path);
229 virCommandAddArgBuffer(cmd, &buf);
230
231 /* If the target does not exist, we're going to create it possibly */
232 if (!virFileExists(snapdisk->src->path))
233 ignore_value(virBitmapSetBit(created, i));
234
235 if (virCommandRun(cmd, NULL) < 0)
236 goto cleanup;
237
238 virCommandFree(cmd);
239 cmd = NULL;
240 }
241
242 /* update disk definitions */
243 for (i = 0; i < snapdef->ndisks; i++) {
244 g_autoptr(virStorageSource) newsrc = NULL;
245
246 snapdisk = &(snapdef->disks[i]);
247 defdisk = vm->def->disks[i];
248
249 if (snapdisk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
250 continue;
251
252 if (!(newsrc = virStorageSourceCopy(snapdisk->src, false)))
253 goto cleanup;
254
255 if (virStorageSourceInitChainElement(newsrc, defdisk->src, false) < 0)
256 goto cleanup;
257
258 if (!reuse &&
259 virStorageSourceHasBacking(defdisk->src)) {
260 defdisk->src->readonly = true;
261 newsrc->backingStore = g_steal_pointer(&defdisk->src);
262 } else {
263 virObjectUnref(defdisk->src);
264 }
265
266 defdisk->src = g_steal_pointer(&newsrc);
267 }
268
269 if (virDomainDefSave(vm->def, driver->xmlopt, cfg->configDir) < 0)
270 goto cleanup;
271
272 ret = 0;
273
274 cleanup:
275 virCommandFree(cmd);
276
277 /* unlink images if creation has failed */
278 if (ret < 0 && created) {
279 ssize_t bit = -1;
280 while ((bit = virBitmapNextSetBit(created, bit)) >= 0) {
281 snapdisk = &(snapdef->disks[bit]);
282 if (unlink(snapdisk->src->path) < 0)
283 VIR_WARN("Failed to remove snapshot image '%s'",
284 snapdisk->src->path);
285 }
286 }
287 virBitmapFree(created);
288
289 return ret;
290 }
291
292
293 /* The domain is expected to be locked and active. */
294 static int
qemuSnapshotCreateActiveInternal(virQEMUDriver * driver,virDomainObj * vm,virDomainMomentObj * snap,unsigned int flags)295 qemuSnapshotCreateActiveInternal(virQEMUDriver *driver,
296 virDomainObj *vm,
297 virDomainMomentObj *snap,
298 unsigned int flags)
299 {
300 qemuDomainObjPrivate *priv = vm->privateData;
301 virObjectEvent *event = NULL;
302 bool resume = false;
303 virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(snap);
304 int ret = -1;
305
306 if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
307 goto cleanup;
308
309 if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
310 /* savevm monitor command pauses the domain emitting an event which
311 * confuses libvirt since it's not notified when qemu resumes the
312 * domain. Thus we stop and start CPUs ourselves.
313 */
314 if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
315 QEMU_ASYNC_JOB_SNAPSHOT) < 0)
316 goto cleanup;
317
318 resume = true;
319 if (!virDomainObjIsActive(vm)) {
320 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
321 _("guest unexpectedly quit"));
322 goto cleanup;
323 }
324 }
325
326 if (qemuDomainObjEnterMonitorAsync(driver, vm,
327 QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
328 resume = false;
329 goto cleanup;
330 }
331
332 ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
333 if (qemuDomainObjExitMonitor(driver, vm) < 0)
334 ret = -1;
335 if (ret < 0)
336 goto cleanup;
337
338 if (!(snapdef->cookie = (virObject *) qemuDomainSaveCookieNew(vm)))
339 goto cleanup;
340
341 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
342 event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
343 VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
344 qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT,
345 QEMU_ASYNC_JOB_SNAPSHOT, 0);
346 virDomainAuditStop(vm, "from-snapshot");
347 resume = false;
348 }
349
350 cleanup:
351 if (resume && virDomainObjIsActive(vm) &&
352 qemuProcessStartCPUs(driver, vm,
353 VIR_DOMAIN_RUNNING_UNPAUSED,
354 QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
355 event = virDomainEventLifecycleNewFromObj(vm,
356 VIR_DOMAIN_EVENT_SUSPENDED,
357 VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
358 if (virGetLastErrorCode() == VIR_ERR_OK) {
359 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
360 _("resuming after snapshot failed"));
361 }
362 }
363
364 virObjectEventStateQueue(driver->domainEventState, event);
365
366 return ret;
367 }
368
369
370 static int
qemuSnapshotPrepareDiskShared(virDomainSnapshotDiskDef * snapdisk,virDomainDiskDef * domdisk)371 qemuSnapshotPrepareDiskShared(virDomainSnapshotDiskDef *snapdisk,
372 virDomainDiskDef *domdisk)
373 {
374 if (!domdisk->src->shared || domdisk->src->readonly)
375 return 0;
376
377 if (!qemuBlockStorageSourceSupportsConcurrentAccess(snapdisk->src)) {
378 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
379 _("shared access for disk '%s' requires use of "
380 "supported storage format"), domdisk->dst);
381 return -1;
382 }
383
384 return 0;
385 }
386
387
388 static int
qemuSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDef * snapdisk,virDomainDiskDef * domdisk)389 qemuSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDef *snapdisk,
390 virDomainDiskDef *domdisk)
391 {
392 int domDiskType = virStorageSourceGetActualType(domdisk->src);
393 int snapDiskType = virStorageSourceGetActualType(snapdisk->src);
394
395 switch ((virStorageType)domDiskType) {
396 case VIR_STORAGE_TYPE_BLOCK:
397 case VIR_STORAGE_TYPE_FILE:
398 break;
399
400 case VIR_STORAGE_TYPE_NETWORK:
401 switch ((virStorageNetProtocol) domdisk->src->protocol) {
402 case VIR_STORAGE_NET_PROTOCOL_NONE:
403 case VIR_STORAGE_NET_PROTOCOL_NBD:
404 case VIR_STORAGE_NET_PROTOCOL_RBD:
405 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
406 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
407 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
408 case VIR_STORAGE_NET_PROTOCOL_HTTP:
409 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
410 case VIR_STORAGE_NET_PROTOCOL_FTP:
411 case VIR_STORAGE_NET_PROTOCOL_FTPS:
412 case VIR_STORAGE_NET_PROTOCOL_TFTP:
413 case VIR_STORAGE_NET_PROTOCOL_SSH:
414 case VIR_STORAGE_NET_PROTOCOL_VXHS:
415 case VIR_STORAGE_NET_PROTOCOL_NFS:
416 case VIR_STORAGE_NET_PROTOCOL_LAST:
417 virReportError(VIR_ERR_INTERNAL_ERROR,
418 _("external inactive snapshots are not supported on "
419 "'network' disks using '%s' protocol"),
420 virStorageNetProtocolTypeToString(domdisk->src->protocol));
421 return -1;
422 }
423 break;
424
425 case VIR_STORAGE_TYPE_DIR:
426 case VIR_STORAGE_TYPE_VOLUME:
427 case VIR_STORAGE_TYPE_NVME:
428 case VIR_STORAGE_TYPE_VHOST_USER:
429 case VIR_STORAGE_TYPE_NONE:
430 case VIR_STORAGE_TYPE_LAST:
431 virReportError(VIR_ERR_INTERNAL_ERROR,
432 _("external inactive snapshots are not supported on "
433 "'%s' disks"), virStorageTypeToString(domDiskType));
434 return -1;
435 }
436
437 switch ((virStorageType)snapDiskType) {
438 case VIR_STORAGE_TYPE_BLOCK:
439 case VIR_STORAGE_TYPE_FILE:
440 break;
441
442 case VIR_STORAGE_TYPE_NETWORK:
443 case VIR_STORAGE_TYPE_DIR:
444 case VIR_STORAGE_TYPE_VOLUME:
445 case VIR_STORAGE_TYPE_NVME:
446 case VIR_STORAGE_TYPE_VHOST_USER:
447 case VIR_STORAGE_TYPE_NONE:
448 case VIR_STORAGE_TYPE_LAST:
449 virReportError(VIR_ERR_INTERNAL_ERROR,
450 _("external inactive snapshots are not supported on "
451 "'%s' disks"), virStorageTypeToString(snapDiskType));
452 return -1;
453 }
454
455 if (qemuSnapshotPrepareDiskShared(snapdisk, domdisk) < 0)
456 return -1;
457
458 return 0;
459 }
460
461
462 static int
qemuSnapshotPrepareDiskExternalActive(virDomainObj * vm,virDomainSnapshotDiskDef * snapdisk,virDomainDiskDef * domdisk,bool blockdev)463 qemuSnapshotPrepareDiskExternalActive(virDomainObj *vm,
464 virDomainSnapshotDiskDef *snapdisk,
465 virDomainDiskDef *domdisk,
466 bool blockdev)
467 {
468 int actualType = virStorageSourceGetActualType(snapdisk->src);
469
470 if (domdisk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
471 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
472 _("external active snapshots are not supported on scsi "
473 "passthrough devices"));
474 return -1;
475 }
476
477 if (!qemuDomainDiskBlockJobIsSupported(vm, domdisk))
478 return -1;
479
480 switch ((virStorageType)actualType) {
481 case VIR_STORAGE_TYPE_BLOCK:
482 case VIR_STORAGE_TYPE_FILE:
483 break;
484
485 case VIR_STORAGE_TYPE_NETWORK:
486 /* defer all of the checking to either qemu or libvirt's blockdev code */
487 if (blockdev)
488 break;
489
490 switch ((virStorageNetProtocol) snapdisk->src->protocol) {
491 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
492 break;
493
494 case VIR_STORAGE_NET_PROTOCOL_NONE:
495 case VIR_STORAGE_NET_PROTOCOL_NBD:
496 case VIR_STORAGE_NET_PROTOCOL_RBD:
497 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
498 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
499 case VIR_STORAGE_NET_PROTOCOL_HTTP:
500 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
501 case VIR_STORAGE_NET_PROTOCOL_FTP:
502 case VIR_STORAGE_NET_PROTOCOL_FTPS:
503 case VIR_STORAGE_NET_PROTOCOL_TFTP:
504 case VIR_STORAGE_NET_PROTOCOL_SSH:
505 case VIR_STORAGE_NET_PROTOCOL_VXHS:
506 case VIR_STORAGE_NET_PROTOCOL_NFS:
507 case VIR_STORAGE_NET_PROTOCOL_LAST:
508 virReportError(VIR_ERR_INTERNAL_ERROR,
509 _("external active snapshots are not supported on "
510 "'network' disks using '%s' protocol"),
511 virStorageNetProtocolTypeToString(snapdisk->src->protocol));
512 return -1;
513
514 }
515 break;
516
517 case VIR_STORAGE_TYPE_DIR:
518 case VIR_STORAGE_TYPE_VOLUME:
519 case VIR_STORAGE_TYPE_NVME:
520 case VIR_STORAGE_TYPE_VHOST_USER:
521 case VIR_STORAGE_TYPE_NONE:
522 case VIR_STORAGE_TYPE_LAST:
523 virReportError(VIR_ERR_INTERNAL_ERROR,
524 _("external active snapshots are not supported on "
525 "'%s' disks"), virStorageTypeToString(actualType));
526 return -1;
527 }
528
529 if (qemuSnapshotPrepareDiskShared(snapdisk, domdisk) < 0)
530 return -1;
531
532 return 0;
533 }
534
535
536 static int
qemuSnapshotPrepareDiskExternal(virDomainObj * vm,virDomainDiskDef * disk,virDomainSnapshotDiskDef * snapdisk,bool active,bool reuse,bool blockdev)537 qemuSnapshotPrepareDiskExternal(virDomainObj *vm,
538 virDomainDiskDef *disk,
539 virDomainSnapshotDiskDef *snapdisk,
540 bool active,
541 bool reuse,
542 bool blockdev)
543 {
544
545 if (disk->src->readonly && !(reuse || blockdev)) {
546 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
547 _("external snapshot for readonly disk %s "
548 "is not supported"), disk->dst);
549 return -1;
550 }
551
552 if (qemuTranslateSnapshotDiskSourcePool(snapdisk) < 0)
553 return -1;
554
555 if (!active) {
556 if (virDomainDiskTranslateSourcePool(disk) < 0)
557 return -1;
558
559 if (qemuSnapshotPrepareDiskExternalInactive(snapdisk, disk) < 0)
560 return -1;
561 } else {
562 if (qemuSnapshotPrepareDiskExternalActive(vm, snapdisk, disk, blockdev) < 0)
563 return -1;
564 }
565
566 if (virStorageSourceIsLocalStorage(snapdisk->src)) {
567 struct stat st;
568 int err;
569 int rc;
570
571 if (virStorageSourceInit(snapdisk->src) < 0)
572 return -1;
573
574 rc = virStorageSourceStat(snapdisk->src, &st);
575 err = errno;
576
577 virStorageSourceDeinit(snapdisk->src);
578
579 if (rc < 0) {
580 if (err != ENOENT) {
581 virReportSystemError(err,
582 _("unable to stat for disk %s: %s"),
583 snapdisk->name, snapdisk->src->path);
584 return -1;
585 }
586
587 if (reuse) {
588 virReportSystemError(err,
589 _("missing existing file for disk %s: %s"),
590 snapdisk->name, snapdisk->src->path);
591 return -1;
592 } else {
593 if (snapdisk->src->type == VIR_STORAGE_TYPE_BLOCK) {
594 virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
595 _("block device snapshot target '%s' doesn't exist"),
596 snapdisk->src->path);
597 return -1;
598 }
599 }
600 } else {
601 /* at this point VIR_STORAGE_TYPE_DIR was already rejected */
602 if ((snapdisk->src->type == VIR_STORAGE_TYPE_BLOCK && !S_ISBLK(st.st_mode)) ||
603 (snapdisk->src->type == VIR_STORAGE_TYPE_FILE && !S_ISREG(st.st_mode))) {
604 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
605 _("mismatch between configured type for snapshot disk '%s' and the type of existing file '%s'"),
606 snapdisk->name, snapdisk->src->path);
607 return -1;
608 }
609
610 if (!reuse &&
611 snapdisk->src->type == VIR_STORAGE_TYPE_FILE &&
612 st.st_size > 0) {
613 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
614 _("external snapshot file for disk %s already exists and is not a block device: %s"),
615 snapdisk->name, snapdisk->src->path);
616 return -1;
617 }
618 }
619 }
620
621 return 0;
622 }
623
624
625 static int
qemuSnapshotPrepareDiskInternal(virDomainDiskDef * disk,bool active)626 qemuSnapshotPrepareDiskInternal(virDomainDiskDef *disk,
627 bool active)
628 {
629 int actualType;
630
631 /* active disks are handled by qemu itself so no need to worry about those */
632 if (active)
633 return 0;
634
635 if (virDomainDiskTranslateSourcePool(disk) < 0)
636 return -1;
637
638 actualType = virStorageSourceGetActualType(disk->src);
639
640 switch ((virStorageType)actualType) {
641 case VIR_STORAGE_TYPE_BLOCK:
642 case VIR_STORAGE_TYPE_FILE:
643 return 0;
644
645 case VIR_STORAGE_TYPE_NETWORK:
646 switch ((virStorageNetProtocol) disk->src->protocol) {
647 case VIR_STORAGE_NET_PROTOCOL_NONE:
648 case VIR_STORAGE_NET_PROTOCOL_NBD:
649 case VIR_STORAGE_NET_PROTOCOL_RBD:
650 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
651 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
652 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
653 case VIR_STORAGE_NET_PROTOCOL_HTTP:
654 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
655 case VIR_STORAGE_NET_PROTOCOL_FTP:
656 case VIR_STORAGE_NET_PROTOCOL_FTPS:
657 case VIR_STORAGE_NET_PROTOCOL_TFTP:
658 case VIR_STORAGE_NET_PROTOCOL_SSH:
659 case VIR_STORAGE_NET_PROTOCOL_VXHS:
660 case VIR_STORAGE_NET_PROTOCOL_NFS:
661 case VIR_STORAGE_NET_PROTOCOL_LAST:
662 virReportError(VIR_ERR_INTERNAL_ERROR,
663 _("internal inactive snapshots are not supported on "
664 "'network' disks using '%s' protocol"),
665 virStorageNetProtocolTypeToString(disk->src->protocol));
666 return -1;
667 }
668 break;
669
670 case VIR_STORAGE_TYPE_DIR:
671 case VIR_STORAGE_TYPE_VOLUME:
672 case VIR_STORAGE_TYPE_NVME:
673 case VIR_STORAGE_TYPE_VHOST_USER:
674 case VIR_STORAGE_TYPE_NONE:
675 case VIR_STORAGE_TYPE_LAST:
676 virReportError(VIR_ERR_INTERNAL_ERROR,
677 _("internal inactive snapshots are not supported on "
678 "'%s' disks"), virStorageTypeToString(actualType));
679 return -1;
680 }
681
682 return 0;
683 }
684
685
686 static int
qemuSnapshotPrepare(virDomainObj * vm,virDomainSnapshotDef * def,unsigned int * flags)687 qemuSnapshotPrepare(virDomainObj *vm,
688 virDomainSnapshotDef *def,
689 unsigned int *flags)
690 {
691 qemuDomainObjPrivate *priv = vm->privateData;
692 bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
693 size_t i;
694 bool active = virDomainObjIsActive(vm);
695 bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
696 bool found_internal = false;
697 bool forbid_internal = false;
698 int external = 0;
699
700 for (i = 0; i < def->ndisks; i++) {
701 virDomainSnapshotDiskDef *disk = &def->disks[i];
702 virDomainDiskDef *dom_disk = vm->def->disks[i];
703
704 if (disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_NONE &&
705 qemuDomainDiskBlockJobIsActive(dom_disk))
706 return -1;
707
708 switch ((virDomainSnapshotLocation) disk->snapshot) {
709 case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
710 found_internal = true;
711
712 if (def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT && active) {
713 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
714 _("active qemu domains require external disk "
715 "snapshots; disk %s requested internal"),
716 disk->name);
717 return -1;
718 }
719
720 if (qemuSnapshotPrepareDiskInternal(dom_disk,
721 active) < 0)
722 return -1;
723
724 if (dom_disk->src->format > 0 &&
725 dom_disk->src->format != VIR_STORAGE_FILE_QCOW2) {
726 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
727 _("internal snapshot for disk %s unsupported "
728 "for storage type %s"),
729 disk->name,
730 virStorageFileFormatTypeToString(dom_disk->src->format));
731 return -1;
732 }
733 break;
734
735 case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
736 if (!disk->src->format) {
737 disk->src->format = VIR_STORAGE_FILE_QCOW2;
738 } else if (disk->src->format != VIR_STORAGE_FILE_QCOW2 &&
739 disk->src->format != VIR_STORAGE_FILE_QED) {
740 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
741 _("external snapshot format for disk %s "
742 "is unsupported: %s"),
743 disk->name,
744 virStorageFileFormatTypeToString(disk->src->format));
745 return -1;
746 }
747
748 if (disk->src->metadataCacheMaxSize > 0) {
749 if (disk->src->format != VIR_STORAGE_FILE_QCOW2) {
750 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
751 _("metadata cache max size control is supported only with qcow2 images"));
752 return -1;
753 }
754
755 if (!blockdev) {
756 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
757 _("metadata cache max size control is not supported with this QEMU binary"));
758 return -1;
759 }
760 }
761
762 if (qemuSnapshotPrepareDiskExternal(vm, dom_disk, disk,
763 active, reuse, blockdev) < 0)
764 return -1;
765
766 external++;
767 break;
768
769 case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
770 /* Remember seeing a disk that has snapshot disabled */
771 if (!virStorageSourceIsEmpty(dom_disk->src) &&
772 !dom_disk->src->readonly)
773 forbid_internal = true;
774 break;
775
776 case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
777 case VIR_DOMAIN_SNAPSHOT_LOCATION_LAST:
778 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
779 _("unexpected code path"));
780 return -1;
781 }
782 }
783
784 if (!found_internal && !external &&
785 def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE) {
786 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
787 _("nothing selected for snapshot"));
788 return -1;
789 }
790
791 /* internal snapshot requires a disk image to store the memory image to, and
792 * also disks can't be excluded from an internal snapshot */
793 if ((def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL && !found_internal) ||
794 (found_internal && forbid_internal)) {
795 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
796 _("internal and full system snapshots require all "
797 "disks to be selected for snapshot"));
798 return -1;
799 }
800
801 /* disk snapshot requires at least one disk */
802 if (def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT && !external) {
803 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
804 _("disk-only snapshots require at least "
805 "one disk to be selected for snapshot"));
806 return -1;
807 }
808
809 /* For now, we don't allow mixing internal and external disks.
810 * XXX technically, we could mix internal and external disks for
811 * offline snapshots */
812 if ((found_internal && external) ||
813 (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL && external) ||
814 (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL && found_internal)) {
815 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
816 _("mixing internal and external targets for a snapshot "
817 "is not yet supported"));
818 return -1;
819 }
820
821 /* internal snapshots + pflash based loader have the following problems:
822 * - if the variable store is raw, the snapshot fails
823 * - allowing a qcow2 image as the varstore would make it eligible to receive
824 * the vmstate dump, which would make it huge
825 * - offline snapshot would not snapshot the varstore at all
826 *
827 * Avoid the issues by forbidding internal snapshot with pflash completely.
828 */
829 if (found_internal &&
830 virDomainDefHasOldStyleUEFI(vm->def)) {
831 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
832 _("internal snapshots of a VM with pflash based "
833 "firmware are not supported"));
834 return -1;
835 }
836
837 /* Alter flags to let later users know what we learned. */
838 if (external && !active)
839 *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;
840
841 return 0;
842 }
843
844
845 struct _qemuSnapshotDiskData {
846 virStorageSource *src;
847 bool initialized; /* @src was initialized in the storage driver */
848 bool created; /* @src was created by the snapshot code */
849 bool prepared; /* @src was prepared using qemuDomainStorageSourceAccessAllow */
850 virDomainDiskDef *disk;
851 char *relPath; /* relative path component to fill into original disk */
852 qemuBlockStorageSourceChainData *crdata;
853 bool blockdevadded;
854
855 virStorageSource *persistsrc;
856 virDomainDiskDef *persistdisk;
857 };
858
859 typedef struct _qemuSnapshotDiskData qemuSnapshotDiskData;
860
861
862 static void
qemuSnapshotDiskCleanup(qemuSnapshotDiskData * data,size_t ndata,virDomainObj * vm,qemuDomainAsyncJob asyncJob)863 qemuSnapshotDiskCleanup(qemuSnapshotDiskData *data,
864 size_t ndata,
865 virDomainObj *vm,
866 qemuDomainAsyncJob asyncJob)
867 {
868 qemuDomainObjPrivate *priv = vm->privateData;
869 virQEMUDriver *driver = priv->driver;
870 virErrorPtr orig_err;
871 size_t i;
872
873 if (!data)
874 return;
875
876 virErrorPreserveLast(&orig_err);
877
878 for (i = 0; i < ndata; i++) {
879 /* on success of the snapshot the 'src' and 'persistsrc' properties will
880 * be set to NULL by qemuSnapshotDiskUpdateSource */
881 if (data[i].src) {
882 if (data[i].blockdevadded) {
883 if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
884
885 qemuBlockStorageSourceAttachRollback(qemuDomainGetMonitor(vm),
886 data[i].crdata->srcdata[0]);
887 ignore_value(qemuDomainObjExitMonitor(driver, vm));
888 }
889 }
890
891 if (data[i].created &&
892 virStorageSourceUnlink(data[i].src) < 0) {
893 VIR_WARN("Unable to remove just-created %s",
894 NULLSTR(data[i].src->path));
895 }
896
897 if (data[i].initialized)
898 virStorageSourceDeinit(data[i].src);
899
900 if (data[i].prepared)
901 qemuDomainStorageSourceAccessRevoke(driver, vm, data[i].src);
902
903 virObjectUnref(data[i].src);
904 }
905 virObjectUnref(data[i].persistsrc);
906 VIR_FREE(data[i].relPath);
907 qemuBlockStorageSourceChainDataFree(data[i].crdata);
908 }
909
910 VIR_FREE(data);
911 virErrorRestore(&orig_err);
912 }
913
914
915 struct _qemuSnapshotDiskContext {
916 qemuSnapshotDiskData *dd;
917 size_t ndd;
918
919 virJSONValue *actions;
920
921 virQEMUDriverConfig *cfg;
922
923 /* needed for automatic cleanup of 'dd' */
924 virDomainObj *vm;
925 qemuDomainAsyncJob asyncJob;
926 };
927
928 typedef struct _qemuSnapshotDiskContext qemuSnapshotDiskContext;
929
930
931 qemuSnapshotDiskContext *
qemuSnapshotDiskContextNew(size_t ndisks,virDomainObj * vm,qemuDomainAsyncJob asyncJob)932 qemuSnapshotDiskContextNew(size_t ndisks,
933 virDomainObj *vm,
934 qemuDomainAsyncJob asyncJob)
935 {
936 qemuDomainObjPrivate *priv = vm->privateData;
937 virQEMUDriver *driver = priv->driver;
938 qemuSnapshotDiskContext *ret = g_new0(qemuSnapshotDiskContext, 1);
939
940 ret->dd = g_new0(qemuSnapshotDiskData, ndisks);
941 ret->actions = virJSONValueNewArray();
942 ret->vm = vm;
943 ret->cfg = virQEMUDriverGetConfig(driver);
944 ret->asyncJob = asyncJob;
945
946 return ret;
947 }
948
949
950 void
qemuSnapshotDiskContextCleanup(qemuSnapshotDiskContext * snapctxt)951 qemuSnapshotDiskContextCleanup(qemuSnapshotDiskContext *snapctxt)
952 {
953 if (!snapctxt)
954 return;
955
956 virJSONValueFree(snapctxt->actions);
957
958 qemuSnapshotDiskCleanup(snapctxt->dd, snapctxt->ndd, snapctxt->vm, snapctxt->asyncJob);
959
960 virObjectUnref(snapctxt->cfg);
961
962 g_free(snapctxt);
963 }
964
965
966 /**
967 * qemuSnapshotDiskBitmapsPropagate:
968 *
969 * This function propagates any active persistent bitmap present in the original
970 * image into the new snapshot. This is necessary to keep tracking the changed
971 * blocks in the active bitmaps as the backing file will become read-only.
972 * We leave the original bitmap active as in cases when the overlay is
973 * discarded (snapshot revert with abandoning the history) everything works as
974 * expected.
975 */
976 static int
qemuSnapshotDiskBitmapsPropagate(qemuSnapshotDiskData * dd,virJSONValue * actions,GHashTable * blockNamedNodeData)977 qemuSnapshotDiskBitmapsPropagate(qemuSnapshotDiskData *dd,
978 virJSONValue *actions,
979 GHashTable *blockNamedNodeData)
980 {
981 qemuBlockNamedNodeData *entry;
982 size_t i;
983
984 if (!(entry = virHashLookup(blockNamedNodeData, dd->disk->src->nodeformat)))
985 return 0;
986
987 for (i = 0; i < entry->nbitmaps; i++) {
988 qemuBlockNamedNodeDataBitmap *bitmap = entry->bitmaps[i];
989
990 /* we don't care about temporary, inconsistent, or disabled bitmaps */
991 if (!bitmap->persistent || !bitmap->recording || bitmap->inconsistent)
992 continue;
993
994 if (qemuMonitorTransactionBitmapAdd(actions, dd->src->nodeformat,
995 bitmap->name, true, false,
996 bitmap->granularity) < 0)
997 return -1;
998 }
999
1000 return 0;
1001 }
1002
1003
1004 static int
qemuSnapshotDiskPrepareOneBlockdev(virQEMUDriver * driver,virDomainObj * vm,qemuSnapshotDiskData * dd,virQEMUDriverConfig * cfg,bool reuse,GHashTable * blockNamedNodeData,qemuDomainAsyncJob asyncJob)1005 qemuSnapshotDiskPrepareOneBlockdev(virQEMUDriver *driver,
1006 virDomainObj *vm,
1007 qemuSnapshotDiskData *dd,
1008 virQEMUDriverConfig *cfg,
1009 bool reuse,
1010 GHashTable *blockNamedNodeData,
1011 qemuDomainAsyncJob asyncJob)
1012 {
1013 qemuDomainObjPrivate *priv = vm->privateData;
1014 g_autoptr(virStorageSource) terminator = NULL;
1015 int rc;
1016
1017 /* create a terminator for the snapshot disks so that qemu does not try
1018 * to open them at first */
1019 terminator = virStorageSourceNew();
1020
1021 if (qemuDomainPrepareStorageSourceBlockdev(dd->disk, dd->src,
1022 priv, cfg) < 0)
1023 return -1;
1024
1025 if (!(dd->crdata = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(dd->src,
1026 terminator)))
1027 return -1;
1028
1029 if (reuse) {
1030 if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
1031 return -1;
1032
1033 rc = qemuBlockStorageSourceAttachApply(qemuDomainGetMonitor(vm),
1034 dd->crdata->srcdata[0]);
1035
1036 if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
1037 return -1;
1038 } else {
1039 if (qemuBlockStorageSourceCreateDetectSize(blockNamedNodeData,
1040 dd->src, dd->disk->src) < 0)
1041 return -1;
1042
1043 if (qemuBlockStorageSourceCreate(vm, dd->src, dd->disk->src,
1044 NULL, dd->crdata->srcdata[0],
1045 asyncJob) < 0)
1046 return -1;
1047 }
1048
1049 dd->blockdevadded = true;
1050 return 0;
1051 }
1052
1053
1054 int
qemuSnapshotDiskPrepareOne(qemuSnapshotDiskContext * snapctxt,virDomainDiskDef * disk,virDomainSnapshotDiskDef * snapdisk,GHashTable * blockNamedNodeData,bool reuse,bool updateConfig)1055 qemuSnapshotDiskPrepareOne(qemuSnapshotDiskContext *snapctxt,
1056 virDomainDiskDef *disk,
1057 virDomainSnapshotDiskDef *snapdisk,
1058 GHashTable *blockNamedNodeData,
1059 bool reuse,
1060 bool updateConfig)
1061 {
1062 virDomainObj *vm = snapctxt->vm;
1063 qemuDomainObjPrivate *priv = vm->privateData;
1064 virQEMUDriver *driver = priv->driver;
1065 bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
1066 virDomainDiskDef *persistdisk;
1067 bool supportsCreate;
1068 bool updateRelativeBacking = false;
1069 qemuSnapshotDiskData *dd = snapctxt->dd + snapctxt->ndd++;
1070
1071 dd->disk = disk;
1072
1073 if (qemuDomainStorageSourceValidateDepth(disk->src, 1, disk->dst) < 0)
1074 return -1;
1075
1076 if (!(dd->src = virStorageSourceCopy(snapdisk->src, false)))
1077 return -1;
1078
1079 if (virStorageSourceInitChainElement(dd->src, dd->disk->src, false) < 0)
1080 return -1;
1081
1082 /* modify disk in persistent definition only when the source is the same */
1083 if (updateConfig &&
1084 vm->newDef &&
1085 (persistdisk = virDomainDiskByTarget(vm->newDef, dd->disk->dst)) &&
1086 virStorageSourceIsSameLocation(dd->disk->src, persistdisk->src)) {
1087
1088 dd->persistdisk = persistdisk;
1089
1090 if (!(dd->persistsrc = virStorageSourceCopy(dd->src, false)))
1091 return -1;
1092
1093 if (virStorageSourceInitChainElement(dd->persistsrc,
1094 dd->persistdisk->src, false) < 0)
1095 return -1;
1096 }
1097
1098 supportsCreate = virStorageSourceSupportsCreate(dd->src);
1099
1100 /* relative backing store paths need to be updated so that relative
1101 * block commit still works. With blockdev we must update it when doing
1102 * commit anyways so it's skipped here */
1103 if (!blockdev &&
1104 virStorageSourceSupportsBackingChainTraversal(dd->src))
1105 updateRelativeBacking = true;
1106
1107 if (supportsCreate || updateRelativeBacking) {
1108 if (qemuDomainStorageFileInit(driver, vm, dd->src, NULL) < 0)
1109 return -1;
1110
1111 dd->initialized = true;
1112
1113 if (reuse) {
1114 if (updateRelativeBacking &&
1115 virStorageSourceFetchRelativeBackingPath(dd->src, &dd->relPath) < 0)
1116 return -1;
1117 } else {
1118 /* pre-create the image file so that we can label it before handing it to qemu */
1119 if (supportsCreate && dd->src->type != VIR_STORAGE_TYPE_BLOCK) {
1120 if (virStorageSourceCreate(dd->src) < 0) {
1121 virReportSystemError(errno, _("failed to create image file '%s'"),
1122 NULLSTR(dd->src->path));
1123 return -1;
1124 }
1125 dd->created = true;
1126 }
1127 }
1128 }
1129
1130 /* set correct security, cgroup and locking options on the new image */
1131 if (qemuDomainStorageSourceAccessAllow(driver, vm, dd->src,
1132 false, true, true) < 0)
1133 return -1;
1134
1135 dd->prepared = true;
1136
1137 if (blockdev) {
1138 if (qemuSnapshotDiskPrepareOneBlockdev(driver, vm, dd, snapctxt->cfg, reuse,
1139 blockNamedNodeData, snapctxt->asyncJob) < 0)
1140 return -1;
1141
1142 if (qemuSnapshotDiskBitmapsPropagate(dd, snapctxt->actions, blockNamedNodeData) < 0)
1143 return -1;
1144
1145 if (qemuBlockSnapshotAddBlockdev(snapctxt->actions, dd->disk, dd->src) < 0)
1146 return -1;
1147 } else {
1148 if (qemuBlockSnapshotAddLegacy(snapctxt->actions, dd->disk, dd->src, reuse) < 0)
1149 return -1;
1150 }
1151
1152 return 0;
1153 }
1154
1155
1156 /**
1157 * qemuSnapshotDiskPrepareActiveExternal:
1158 *
1159 * Collects and prepares a list of structures that hold information about disks
1160 * that are selected for the snapshot.
1161 */
1162 static qemuSnapshotDiskContext *
qemuSnapshotDiskPrepareActiveExternal(virDomainObj * vm,virDomainMomentObj * snap,bool reuse,GHashTable * blockNamedNodeData,qemuDomainAsyncJob asyncJob)1163 qemuSnapshotDiskPrepareActiveExternal(virDomainObj *vm,
1164 virDomainMomentObj *snap,
1165 bool reuse,
1166 GHashTable *blockNamedNodeData,
1167 qemuDomainAsyncJob asyncJob)
1168 {
1169 g_autoptr(qemuSnapshotDiskContext) snapctxt = NULL;
1170 size_t i;
1171 virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(snap);
1172
1173 snapctxt = qemuSnapshotDiskContextNew(snapdef->ndisks, vm, asyncJob);
1174
1175 for (i = 0; i < snapdef->ndisks; i++) {
1176 if (snapdef->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
1177 continue;
1178
1179 if (qemuSnapshotDiskPrepareOne(snapctxt,
1180 vm->def->disks[i],
1181 snapdef->disks + i,
1182 blockNamedNodeData,
1183 reuse,
1184 true) < 0)
1185 return NULL;
1186 }
1187
1188 return g_steal_pointer(&snapctxt);
1189 }
1190
1191
1192 virDomainSnapshotDiskDef *
qemuSnapshotGetTransientDiskDef(virDomainDiskDef * domdisk,const char * suffix)1193 qemuSnapshotGetTransientDiskDef(virDomainDiskDef *domdisk,
1194 const char *suffix)
1195 {
1196 g_autoptr(virDomainSnapshotDiskDef) snapdisk = g_new0(virDomainSnapshotDiskDef, 1);
1197
1198 snapdisk->name = g_strdup(domdisk->dst);
1199 snapdisk->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
1200 snapdisk->src = virStorageSourceNew();
1201 snapdisk->src->type = VIR_STORAGE_TYPE_FILE;
1202 snapdisk->src->format = VIR_STORAGE_FILE_QCOW2;
1203 snapdisk->src->path = g_strdup_printf("%s.TRANSIENT-%s",
1204 domdisk->src->path, suffix);
1205
1206 if (virFileExists(snapdisk->src->path)) {
1207 virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
1208 _("Overlay file '%s' for transient disk '%s' already exists"),
1209 snapdisk->src->path, domdisk->dst);
1210 return NULL;
1211 }
1212
1213 return g_steal_pointer(&snapdisk);
1214 }
1215
1216
1217 static void
qemuSnapshotDiskUpdateSourceRenumber(virStorageSource * src)1218 qemuSnapshotDiskUpdateSourceRenumber(virStorageSource *src)
1219 {
1220 virStorageSource *next;
1221 unsigned int idx = 1;
1222
1223 for (next = src->backingStore; virStorageSourceIsBacking(next); next = next->backingStore)
1224 next->id = idx++;
1225 }
1226
1227
1228 /**
1229 * qemuSnapshotDiskUpdateSource:
1230 * @vm: domain object
1231 * @dd: snapshot disk data object
1232 *
1233 * Updates disk definition after a successful snapshot.
1234 */
1235 static void
qemuSnapshotDiskUpdateSource(virDomainObj * vm,qemuSnapshotDiskData * dd)1236 qemuSnapshotDiskUpdateSource(virDomainObj *vm,
1237 qemuSnapshotDiskData *dd)
1238 {
1239 qemuDomainObjPrivate *priv = vm->privateData;
1240 virQEMUDriver *driver = priv->driver;
1241
1242 /* storage driver access won'd be needed */
1243 if (dd->initialized)
1244 virStorageSourceDeinit(dd->src);
1245
1246 if (qemuSecurityMoveImageMetadata(driver, vm, dd->disk->src, dd->src) < 0)
1247 VIR_WARN("Unable to move disk metadata on vm %s", vm->def->name);
1248
1249 /* unlock the write lock on the original image as qemu will no longer write to it */
1250 virDomainLockImageDetach(driver->lockManager, vm, dd->disk->src);
1251
1252 /* unlock also the new image if the VM is paused to follow the locking semantics */
1253 if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING)
1254 virDomainLockImageDetach(driver->lockManager, vm, dd->src);
1255
1256 /* the old disk image is now readonly */
1257 dd->disk->src->readonly = true;
1258
1259 dd->disk->src->relPath = g_steal_pointer(&dd->relPath);
1260 dd->src->backingStore = g_steal_pointer(&dd->disk->src);
1261 dd->disk->src = g_steal_pointer(&dd->src);
1262
1263 /* fix numbering of disks */
1264 if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
1265 qemuSnapshotDiskUpdateSourceRenumber(dd->disk->src);
1266
1267 if (dd->persistdisk) {
1268 dd->persistdisk->src->readonly = true;
1269 dd->persistsrc->backingStore = g_steal_pointer(&dd->persistdisk->src);
1270 dd->persistdisk->src = g_steal_pointer(&dd->persistsrc);
1271 }
1272 }
1273
1274
1275 int
qemuSnapshotDiskCreate(qemuSnapshotDiskContext * snapctxt)1276 qemuSnapshotDiskCreate(qemuSnapshotDiskContext *snapctxt)
1277 {
1278 qemuDomainObjPrivate *priv = snapctxt->vm->privateData;
1279 virQEMUDriver *driver = priv->driver;
1280 size_t i;
1281 int rc;
1282
1283 /* check whether there's anything to do */
1284 if (snapctxt->ndd == 0)
1285 return 0;
1286
1287 if (qemuDomainObjEnterMonitorAsync(driver, snapctxt->vm, snapctxt->asyncJob) < 0)
1288 return -1;
1289
1290 rc = qemuMonitorTransaction(priv->mon, &snapctxt->actions);
1291
1292 if (qemuDomainObjExitMonitor(driver, snapctxt->vm) < 0)
1293 rc = -1;
1294
1295 for (i = 0; i < snapctxt->ndd; i++) {
1296 qemuSnapshotDiskData *dd = snapctxt->dd + i;
1297
1298 virDomainAuditDisk(snapctxt->vm, dd->disk->src, dd->src, "snapshot", rc >= 0);
1299
1300 if (rc == 0)
1301 qemuSnapshotDiskUpdateSource(snapctxt->vm, dd);
1302 }
1303
1304 if (rc < 0)
1305 return -1;
1306
1307 if (virDomainObjSave(snapctxt->vm, driver->xmlopt, snapctxt->cfg->stateDir) < 0 ||
1308 (snapctxt->vm->newDef && virDomainDefSave(snapctxt->vm->newDef, driver->xmlopt,
1309 snapctxt->cfg->configDir) < 0))
1310 return -1;
1311
1312 return 0;
1313 }
1314
1315
1316 /* The domain is expected to be locked and active. */
1317 static int
qemuSnapshotCreateActiveExternalDisks(virDomainObj * vm,virDomainMomentObj * snap,GHashTable * blockNamedNodeData,unsigned int flags,qemuDomainAsyncJob asyncJob)1318 qemuSnapshotCreateActiveExternalDisks(virDomainObj *vm,
1319 virDomainMomentObj *snap,
1320 GHashTable *blockNamedNodeData,
1321 unsigned int flags,
1322 qemuDomainAsyncJob asyncJob)
1323 {
1324 bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
1325 g_autoptr(qemuSnapshotDiskContext) snapctxt = NULL;
1326
1327 if (virDomainObjCheckActive(vm) < 0)
1328 return -1;
1329
1330 /* prepare a list of objects to use in the vm definition so that we don't
1331 * have to roll back later */
1332 if (!(snapctxt = qemuSnapshotDiskPrepareActiveExternal(vm, snap, reuse,
1333 blockNamedNodeData, asyncJob)))
1334 return -1;
1335
1336 if (qemuSnapshotDiskCreate(snapctxt) < 0)
1337 return -1;
1338
1339 return 0;
1340 }
1341
1342
1343 static int
qemuSnapshotCreateActiveExternal(virQEMUDriver * driver,virDomainObj * vm,virDomainMomentObj * snap,virQEMUDriverConfig * cfg,unsigned int flags)1344 qemuSnapshotCreateActiveExternal(virQEMUDriver *driver,
1345 virDomainObj *vm,
1346 virDomainMomentObj *snap,
1347 virQEMUDriverConfig *cfg,
1348 unsigned int flags)
1349 {
1350 virObjectEvent *event;
1351 bool resume = false;
1352 int ret = -1;
1353 qemuDomainObjPrivate *priv = vm->privateData;
1354 g_autofree char *xml = NULL;
1355 virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(snap);
1356 bool memory = snapdef->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
1357 bool memory_unlink = false;
1358 bool memory_existing = false;
1359 bool thaw = false;
1360 bool pmsuspended = false;
1361 int compressed;
1362 g_autoptr(virCommand) compressor = NULL;
1363 virQEMUSaveData *data = NULL;
1364 g_autoptr(GHashTable) blockNamedNodeData = NULL;
1365
1366 /* If quiesce was requested, then issue a freeze command, and a
1367 * counterpart thaw command when it is actually sent to agent.
1368 * The command will fail if the guest is paused or the guest agent
1369 * is not running, or is already quiesced. */
1370 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) {
1371 int frozen;
1372
1373 if (qemuDomainObjBeginAgentJob(driver, vm, QEMU_AGENT_JOB_MODIFY) < 0)
1374 goto cleanup;
1375
1376 if (virDomainObjCheckActive(vm) < 0) {
1377 qemuDomainObjEndAgentJob(vm);
1378 goto cleanup;
1379 }
1380
1381 frozen = qemuSnapshotFSFreeze(vm, NULL, 0);
1382 qemuDomainObjEndAgentJob(vm);
1383
1384 if (frozen < 0)
1385 goto cleanup;
1386
1387 if (frozen > 0)
1388 thaw = true;
1389 }
1390
1391 /* We need to track what state the guest is in, since taking the
1392 * snapshot may alter that state and we must restore it later. */
1393 if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PMSUSPENDED) {
1394 pmsuspended = true;
1395 } else if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
1396 /* For full system external snapshots (those with memory), the guest
1397 * must pause (either by libvirt up front, or by qemu after
1398 * _LIVE converges). */
1399 if (memory)
1400 resume = true;
1401
1402 if (memory && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE)) {
1403 if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SNAPSHOT,
1404 QEMU_ASYNC_JOB_SNAPSHOT) < 0)
1405 goto cleanup;
1406
1407 if (!virDomainObjIsActive(vm)) {
1408 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1409 _("guest unexpectedly quit"));
1410 goto cleanup;
1411 }
1412
1413 resume = true;
1414 }
1415 }
1416
1417 /* We need to collect reply from 'query-named-block-nodes' prior to the
1418 * migration step as qemu deactivates bitmaps after migration so the result
1419 * would be wrong */
1420 if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) &&
1421 !(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_SNAPSHOT)))
1422 goto cleanup;
1423
1424 /* do the memory snapshot if necessary */
1425 if (memory) {
1426 /* check if migration is possible */
1427 if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
1428 goto cleanup;
1429
1430 priv->job.current->statsType = QEMU_DOMAIN_JOB_STATS_TYPE_SAVEDUMP;
1431
1432 /* allow the migration job to be cancelled or the domain to be paused */
1433 qemuDomainObjSetAsyncJobMask(vm, (QEMU_JOB_DEFAULT_MASK |
1434 JOB_MASK(QEMU_JOB_SUSPEND) |
1435 JOB_MASK(QEMU_JOB_MIGRATION_OP)));
1436
1437 if ((compressed = qemuSaveImageGetCompressionProgram(cfg->snapshotImageFormat,
1438 &compressor,
1439 "snapshot", false)) < 0)
1440 goto cleanup;
1441
1442 if (!(xml = qemuDomainDefFormatLive(driver, priv->qemuCaps,
1443 vm->def, priv->origCPU,
1444 true, true)) ||
1445 !(snapdef->cookie = (virObject *) qemuDomainSaveCookieNew(vm)))
1446 goto cleanup;
1447
1448 if (!(data = virQEMUSaveDataNew(xml,
1449 (qemuDomainSaveCookie *) snapdef->cookie,
1450 resume, compressed, driver->xmlopt)))
1451 goto cleanup;
1452 xml = NULL;
1453
1454 memory_existing = virFileExists(snapdef->memorysnapshotfile);
1455
1456 if ((ret = qemuSaveImageCreate(driver, vm, snapdef->memorysnapshotfile,
1457 data, compressor, 0,
1458 QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
1459 goto cleanup;
1460
1461 /* the memory image was created, remove it on errors */
1462 if (!memory_existing)
1463 memory_unlink = true;
1464
1465 /* forbid any further manipulation */
1466 qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_DEFAULT_MASK);
1467 }
1468
1469 /* the domain is now paused if a memory snapshot was requested */
1470
1471 if ((ret = qemuSnapshotCreateActiveExternalDisks(vm, snap,
1472 blockNamedNodeData, flags,
1473 QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
1474 goto cleanup;
1475
1476 /* the snapshot is complete now */
1477 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
1478 event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1479 VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
1480 qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT,
1481 QEMU_ASYNC_JOB_SNAPSHOT, 0);
1482 virDomainAuditStop(vm, "from-snapshot");
1483 resume = false;
1484 thaw = false;
1485 virObjectEventStateQueue(driver->domainEventState, event);
1486 } else if (memory && pmsuspended) {
1487 /* qemu 1.3 is unable to save a domain in pm-suspended (S3)
1488 * state; so we must emit an event stating that it was
1489 * converted to paused. */
1490 virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
1491 VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
1492 event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
1493 VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
1494 virObjectEventStateQueue(driver->domainEventState, event);
1495 }
1496
1497 ret = 0;
1498
1499 cleanup:
1500 if (resume && virDomainObjIsActive(vm) &&
1501 qemuProcessStartCPUs(driver, vm,
1502 VIR_DOMAIN_RUNNING_UNPAUSED,
1503 QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
1504 event = virDomainEventLifecycleNewFromObj(vm,
1505 VIR_DOMAIN_EVENT_SUSPENDED,
1506 VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
1507 virObjectEventStateQueue(driver->domainEventState, event);
1508 if (virGetLastErrorCode() == VIR_ERR_OK) {
1509 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1510 _("resuming after snapshot failed"));
1511 }
1512
1513 ret = -1;
1514 }
1515
1516 if (thaw &&
1517 qemuDomainObjBeginAgentJob(driver, vm, QEMU_AGENT_JOB_MODIFY) >= 0 &&
1518 virDomainObjIsActive(vm)) {
1519 /* report error only on an otherwise successful snapshot */
1520 if (qemuSnapshotFSThaw(vm, ret == 0) < 0)
1521 ret = -1;
1522
1523 qemuDomainObjEndAgentJob(vm);
1524 }
1525
1526 virQEMUSaveDataFree(data);
1527 if (memory_unlink && ret < 0)
1528 unlink(snapdef->memorysnapshotfile);
1529
1530 return ret;
1531 }
1532
1533
1534 virDomainSnapshotPtr
qemuSnapshotCreateXML(virDomainPtr domain,virDomainObj * vm,const char * xmlDesc,unsigned int flags)1535 qemuSnapshotCreateXML(virDomainPtr domain,
1536 virDomainObj *vm,
1537 const char *xmlDesc,
1538 unsigned int flags)
1539 {
1540 virQEMUDriver *driver = domain->conn->privateData;
1541 g_autofree char *xml = NULL;
1542 virDomainMomentObj *snap = NULL;
1543 virDomainSnapshotPtr snapshot = NULL;
1544 virDomainMomentObj *current = NULL;
1545 bool update_current = true;
1546 bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
1547 unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
1548 int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
1549 bool align_match = true;
1550 g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
1551 qemuDomainObjPrivate *priv = vm->privateData;
1552 virDomainSnapshotState state;
1553 g_autoptr(virDomainSnapshotDef) def = NULL;
1554
1555 virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
1556 VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
1557 VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
1558 VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
1559 VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
1560 VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
1561 VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
1562 VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
1563 VIR_DOMAIN_SNAPSHOT_CREATE_LIVE |
1564 VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE, NULL);
1565
1566 VIR_REQUIRE_FLAG_RET(VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE,
1567 VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY,
1568 NULL);
1569 VIR_EXCLUSIVE_FLAGS_RET(VIR_DOMAIN_SNAPSHOT_CREATE_LIVE,
1570 VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE,
1571 NULL);
1572
1573 if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
1574 (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
1575 update_current = false;
1576 if (redefine)
1577 parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
1578
1579 if (qemuDomainSupportsCheckpointsBlockjobs(vm) < 0)
1580 return NULL;
1581
1582 if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
1583 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1584 _("cannot halt after transient domain snapshot"));
1585 return NULL;
1586 }
1587 if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
1588 !virDomainObjIsActive(vm))
1589 parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
1590
1591 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE)
1592 parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_VALIDATE;
1593
1594 if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->xmlopt,
1595 priv->qemuCaps, NULL, parse_flags)))
1596 return NULL;
1597
1598 /* reject snapshot names containing slashes or starting with dot as
1599 * snapshot definitions are saved in files named by the snapshot name */
1600 if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
1601 if (strchr(def->parent.name, '/')) {
1602 virReportError(VIR_ERR_XML_DETAIL,
1603 _("invalid snapshot name '%s': "
1604 "name can't contain '/'"),
1605 def->parent.name);
1606 return NULL;
1607 }
1608
1609 if (def->parent.name[0] == '.') {
1610 virReportError(VIR_ERR_XML_DETAIL,
1611 _("invalid snapshot name '%s': "
1612 "name can't start with '.'"),
1613 def->parent.name);
1614 return NULL;
1615 }
1616 }
1617
1618 /* reject the VIR_DOMAIN_SNAPSHOT_CREATE_LIVE flag where not supported */
1619 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE &&
1620 (!virDomainObjIsActive(vm) ||
1621 def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)) {
1622 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
1623 _("live snapshot creation is supported only "
1624 "during full system snapshots"));
1625 return NULL;
1626 }
1627
1628 /* allow snapshots only in certain states */
1629 state = redefine ? def->state : vm->state.state;
1630 switch (state) {
1631 /* valid states */
1632 case VIR_DOMAIN_SNAPSHOT_RUNNING:
1633 case VIR_DOMAIN_SNAPSHOT_PAUSED:
1634 case VIR_DOMAIN_SNAPSHOT_SHUTDOWN:
1635 case VIR_DOMAIN_SNAPSHOT_SHUTOFF:
1636 case VIR_DOMAIN_SNAPSHOT_CRASHED:
1637 break;
1638
1639 case VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT:
1640 if (!redefine) {
1641 virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid domain state %s"),
1642 virDomainSnapshotStateTypeToString(state));
1643 return NULL;
1644 }
1645 break;
1646
1647 case VIR_DOMAIN_SNAPSHOT_PMSUSPENDED:
1648 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
1649 _("qemu doesn't support taking snapshots of "
1650 "PMSUSPENDED guests"));
1651 return NULL;
1652
1653 /* invalid states */
1654 case VIR_DOMAIN_SNAPSHOT_NOSTATE:
1655 case VIR_DOMAIN_SNAPSHOT_BLOCKED: /* invalid state, unused in qemu */
1656 case VIR_DOMAIN_SNAPSHOT_LAST:
1657 virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid domain state %s"),
1658 virDomainSnapshotStateTypeToString(state));
1659 return NULL;
1660 }
1661
1662 /* We are going to modify the domain below. Internal snapshots would use
1663 * a regular job, so we need to set the job mask to disallow query as
1664 * 'savevm' blocks the monitor. External snapshot will then modify the
1665 * job mask appropriately. */
1666 if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SNAPSHOT,
1667 VIR_DOMAIN_JOB_OPERATION_SNAPSHOT, flags) < 0)
1668 return NULL;
1669
1670 qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_NONE);
1671
1672 if (redefine) {
1673 if (virDomainSnapshotRedefinePrep(vm, &def, &snap,
1674 driver->xmlopt,
1675 flags) < 0)
1676 goto endjob;
1677 } else {
1678 /* Easiest way to clone inactive portion of vm->def is via
1679 * conversion in and back out of xml. */
1680 if (!(xml = qemuDomainDefFormatLive(driver, priv->qemuCaps,
1681 vm->def, priv->origCPU,
1682 true, true)) ||
1683 !(def->parent.dom = virDomainDefParseString(xml, driver->xmlopt,
1684 priv->qemuCaps,
1685 VIR_DOMAIN_DEF_PARSE_INACTIVE |
1686 VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
1687 goto endjob;
1688
1689 if (vm->newDef) {
1690 def->parent.inactiveDom = virDomainDefCopy(vm->newDef,
1691 driver->xmlopt, priv->qemuCaps, true);
1692 if (!def->parent.inactiveDom)
1693 goto endjob;
1694 }
1695
1696 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
1697 align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
1698 align_match = false;
1699 if (virDomainObjIsActive(vm))
1700 def->state = VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT;
1701 else
1702 def->state = VIR_DOMAIN_SNAPSHOT_SHUTOFF;
1703 def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
1704 } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
1705 def->state = virDomainObjGetState(vm, NULL);
1706 align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
1707 align_match = false;
1708 } else {
1709 def->state = virDomainObjGetState(vm, NULL);
1710
1711 if (virDomainObjIsActive(vm) &&
1712 def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE) {
1713 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
1714 _("internal snapshot of a running VM "
1715 "must include the memory state"));
1716 goto endjob;
1717 }
1718
1719 def->memory = (def->state == VIR_DOMAIN_SNAPSHOT_SHUTOFF ?
1720 VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
1721 VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
1722 }
1723 if (virDomainSnapshotAlignDisks(def, align_location,
1724 align_match) < 0 ||
1725 qemuSnapshotPrepare(vm, def, &flags) < 0)
1726 goto endjob;
1727 }
1728
1729 if (!snap) {
1730 if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
1731 goto endjob;
1732
1733 def = NULL;
1734 }
1735
1736 current = virDomainSnapshotGetCurrent(vm->snapshots);
1737 if (current) {
1738 if (!redefine)
1739 snap->def->parent_name = g_strdup(current->def->name);
1740 }
1741
1742 /* actually do the snapshot */
1743 if (redefine) {
1744 /* XXX Should we validate that the redefined snapshot even
1745 * makes sense, such as checking that qemu-img recognizes the
1746 * snapshot name in at least one of the domain's disks? */
1747 } else if (virDomainObjIsActive(vm)) {
1748 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY ||
1749 virDomainSnapshotObjGetDef(snap)->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
1750 /* external full system or disk snapshot */
1751 if (qemuSnapshotCreateActiveExternal(driver, vm, snap, cfg, flags) < 0)
1752 goto endjob;
1753 } else {
1754 /* internal full system */
1755 if (qemuSnapshotCreateActiveInternal(driver, vm, snap, flags) < 0)
1756 goto endjob;
1757 }
1758 } else {
1759 /* inactive; qemuSnapshotPrepare guaranteed that we
1760 * aren't mixing internal and external, and altered flags to
1761 * contain DISK_ONLY if there is an external disk. */
1762 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
1763 bool reuse = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
1764
1765 if (qemuSnapshotCreateInactiveExternal(driver, vm, snap, reuse) < 0)
1766 goto endjob;
1767 } else {
1768 if (qemuSnapshotCreateInactiveInternal(driver, vm, snap) < 0)
1769 goto endjob;
1770 }
1771 }
1772
1773 /* If we fail after this point, there's not a whole lot we can
1774 * do; we've successfully taken the snapshot, and we are now running
1775 * on it, so we have to go forward the best we can
1776 */
1777 snapshot = virGetDomainSnapshot(domain, snap->def->name);
1778
1779 endjob:
1780 if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
1781 if (update_current)
1782 qemuSnapshotSetCurrent(vm, snap);
1783
1784 if (qemuDomainSnapshotWriteMetadata(vm, snap,
1785 driver->xmlopt,
1786 cfg->snapshotDir) < 0) {
1787 /* if writing of metadata fails, error out rather than trying
1788 * to silently carry on without completing the snapshot */
1789 virObjectUnref(snapshot);
1790 snapshot = NULL;
1791 virReportError(VIR_ERR_INTERNAL_ERROR,
1792 _("unable to save metadata for snapshot %s"),
1793 snap->def->name);
1794 virDomainSnapshotObjListRemove(vm->snapshots, snap);
1795 } else {
1796 virDomainSnapshotLinkParent(vm->snapshots, snap);
1797 }
1798 } else if (snap) {
1799 virDomainSnapshotObjListRemove(vm->snapshots, snap);
1800 }
1801
1802 qemuDomainObjEndAsyncJob(driver, vm);
1803
1804 return snapshot;
1805 }
1806
1807
1808 /* The domain is expected to be locked and inactive. */
1809 static int
qemuSnapshotRevertInactive(virQEMUDriver * driver,virDomainObj * vm,virDomainMomentObj * snap)1810 qemuSnapshotRevertInactive(virQEMUDriver *driver,
1811 virDomainObj *vm,
1812 virDomainMomentObj *snap)
1813 {
1814 size_t i;
1815
1816 /* Prefer action on the disks in use at the time the snapshot was
1817 * created; but fall back to current definition if dealing with a
1818 * snapshot created prior to libvirt 0.9.5. */
1819 virDomainDef *def = snap->def->dom;
1820
1821 if (!def)
1822 def = vm->def;
1823
1824 for (i = 0; i < def->ndisks; i++) {
1825 if (virDomainDiskTranslateSourcePool(def->disks[i]) < 0)
1826 return -1;
1827 }
1828
1829 /* Try all disks, but report failure if we skipped any. */
1830 if (qemuDomainSnapshotForEachQcow2(driver, def, snap, "-a", true) != 0)
1831 return -1;
1832
1833 return 0;
1834 }
1835
1836
1837 int
qemuSnapshotRevert(virDomainObj * vm,virDomainSnapshotPtr snapshot,unsigned int flags)1838 qemuSnapshotRevert(virDomainObj *vm,
1839 virDomainSnapshotPtr snapshot,
1840 unsigned int flags)
1841 {
1842 virQEMUDriver *driver = snapshot->domain->conn->privateData;
1843 int ret = -1;
1844 virDomainMomentObj *snap = NULL;
1845 virDomainSnapshotDef *snapdef;
1846 virObjectEvent *event = NULL;
1847 virObjectEvent *event2 = NULL;
1848 int detail;
1849 qemuDomainObjPrivate *priv = vm->privateData;
1850 int rc;
1851 virDomainDef *config = NULL;
1852 virDomainDef *inactiveConfig = NULL;
1853 g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
1854 qemuDomainSaveCookie *cookie;
1855 virCPUDef *origCPU = NULL;
1856 unsigned int start_flags = VIR_QEMU_PROCESS_START_GEN_VMID;
1857 bool defined = false;
1858
1859 virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
1860 VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
1861 VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
1862
1863 /* We have the following transitions, which create the following events:
1864 * 1. inactive -> inactive: none
1865 * 2. inactive -> running: EVENT_STARTED
1866 * 3. inactive -> paused: EVENT_STARTED, EVENT_SUSPENDED
1867 * 4. running -> inactive: EVENT_STOPPED
1868 * 5. running -> running: EVENT_STOPPED, EVENT_STARTED
1869 * 6. running -> paused: EVENT_STOPPED, EVENT_STARTED, EVENT_SUSPENDED
1870 * 7. paused -> inactive: EVENT_STOPPED
1871 * 8. paused -> running: EVENT_STOPPED, EVENT_STARTED
1872 * 9. paused -> paused: EVENT_STOPPED, EVENT_STARTED, EVENT_SUSPENDED
1873 * Also, several transitions occur even if we fail partway through.
1874 */
1875
1876 if (qemuDomainHasBlockjob(vm, false)) {
1877 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1878 _("domain has active block job"));
1879 goto cleanup;
1880 }
1881
1882 if (qemuProcessBeginJob(driver, vm,
1883 VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_REVERT,
1884 flags) < 0)
1885 goto cleanup;
1886
1887 if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
1888 goto endjob;
1889 snapdef = virDomainSnapshotObjGetDef(snap);
1890
1891 if (!vm->persistent &&
1892 snapdef->state != VIR_DOMAIN_SNAPSHOT_RUNNING &&
1893 snapdef->state != VIR_DOMAIN_SNAPSHOT_PAUSED &&
1894 (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
1895 VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
1896 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1897 _("transient domain needs to request run or pause "
1898 "to revert to inactive snapshot"));
1899 goto endjob;
1900 }
1901
1902 if (virDomainSnapshotIsExternal(snap)) {
1903 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1904 _("revert to external snapshot not supported yet"));
1905 goto endjob;
1906 }
1907
1908 if (!snap->def->dom) {
1909 virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
1910 _("snapshot '%s' lacks domain '%s' rollback info"),
1911 snap->def->name, vm->def->name);
1912 goto endjob;
1913 }
1914
1915 if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
1916 if (vm->hasManagedSave &&
1917 !(snapdef->state == VIR_DOMAIN_SNAPSHOT_RUNNING ||
1918 snapdef->state == VIR_DOMAIN_SNAPSHOT_PAUSED)) {
1919 virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
1920 _("snapshot without memory state, removal of "
1921 "existing managed saved state strongly "
1922 "recommended to avoid corruption"));
1923 goto endjob;
1924 }
1925 }
1926
1927 config = virDomainDefCopy(snap->def->dom,
1928 driver->xmlopt, priv->qemuCaps, true);
1929 if (!config)
1930 goto endjob;
1931
1932 if (STRNEQ(config->name, vm->def->name)) {
1933 VIR_FREE(config->name);
1934 config->name = g_strdup(vm->def->name);
1935 }
1936
1937 if (snap->def->inactiveDom) {
1938 inactiveConfig = virDomainDefCopy(snap->def->inactiveDom,
1939 driver->xmlopt, priv->qemuCaps, true);
1940 if (!inactiveConfig)
1941 goto endjob;
1942
1943 if (STRNEQ(inactiveConfig->name, vm->def->name)) {
1944 VIR_FREE(inactiveConfig->name);
1945 inactiveConfig->name = g_strdup(vm->def->name);
1946 }
1947 } else {
1948 /* Inactive domain definition is missing:
1949 * - either this is an old active snapshot and we need to copy the
1950 * active definition as an inactive one
1951 * - or this is an inactive snapshot which means config contains the
1952 * inactive definition.
1953 */
1954 if (snapdef->state == VIR_DOMAIN_SNAPSHOT_RUNNING ||
1955 snapdef->state == VIR_DOMAIN_SNAPSHOT_PAUSED) {
1956 inactiveConfig = virDomainDefCopy(snap->def->dom,
1957 driver->xmlopt, priv->qemuCaps, true);
1958 if (!inactiveConfig)
1959 goto endjob;
1960 } else {
1961 inactiveConfig = g_steal_pointer(&config);
1962 }
1963 }
1964
1965 cookie = (qemuDomainSaveCookie *) snapdef->cookie;
1966
1967 switch ((virDomainSnapshotState) snapdef->state) {
1968 case VIR_DOMAIN_SNAPSHOT_RUNNING:
1969 case VIR_DOMAIN_SNAPSHOT_PAUSED:
1970 start_flags |= VIR_QEMU_PROCESS_START_PAUSED;
1971
1972 /* Transitions 2, 3, 5, 6, 8, 9 */
1973 if (virDomainObjIsActive(vm)) {
1974 /* Transitions 5, 6, 8, 9 */
1975 qemuProcessStop(driver, vm,
1976 VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT,
1977 QEMU_ASYNC_JOB_START, 0);
1978 virDomainAuditStop(vm, "from-snapshot");
1979 detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
1980 event = virDomainEventLifecycleNewFromObj(vm,
1981 VIR_DOMAIN_EVENT_STOPPED,
1982 detail);
1983 virObjectEventStateQueue(driver->domainEventState, event);
1984 }
1985
1986 if (inactiveConfig) {
1987 virDomainObjAssignDef(vm, &inactiveConfig, false, NULL);
1988 defined = true;
1989 }
1990
1991 virDomainObjAssignDef(vm, &config, true, NULL);
1992
1993 /* No cookie means libvirt which saved the domain was too old to
1994 * mess up the CPU definitions.
1995 */
1996 if (cookie &&
1997 qemuDomainFixupCPUs(vm, &cookie->cpu) < 0)
1998 goto cleanup;
1999
2000 rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
2001 cookie ? cookie->cpu : NULL,
2002 QEMU_ASYNC_JOB_START, NULL, -1, NULL, snap,
2003 VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
2004 start_flags);
2005 virDomainAuditStart(vm, "from-snapshot", rc >= 0);
2006 detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
2007 event = virDomainEventLifecycleNewFromObj(vm,
2008 VIR_DOMAIN_EVENT_STARTED,
2009 detail);
2010 if (rc < 0)
2011 goto endjob;
2012
2013 /* Touch up domain state. */
2014 if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
2015 (snapdef->state == VIR_DOMAIN_SNAPSHOT_PAUSED ||
2016 (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
2017 /* Transitions 3, 6, 9 */
2018 virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
2019 VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
2020 detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
2021 event2 = virDomainEventLifecycleNewFromObj(vm,
2022 VIR_DOMAIN_EVENT_SUSPENDED,
2023 detail);
2024 } else {
2025 /* Transitions 2, 5, 8 */
2026 if (!virDomainObjIsActive(vm)) {
2027 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2028 _("guest unexpectedly quit"));
2029 goto endjob;
2030 }
2031 rc = qemuProcessStartCPUs(driver, vm,
2032 VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
2033 QEMU_ASYNC_JOB_START);
2034 if (rc < 0)
2035 goto endjob;
2036 }
2037 break;
2038
2039 case VIR_DOMAIN_SNAPSHOT_SHUTDOWN:
2040 case VIR_DOMAIN_SNAPSHOT_SHUTOFF:
2041 case VIR_DOMAIN_SNAPSHOT_CRASHED:
2042 /* Transitions 1, 4, 7 */
2043 /* Newer qemu -loadvm refuses to revert to the state of a snapshot
2044 * created by qemu-img snapshot -c. If the domain is running, we
2045 * must take it offline; then do the revert using qemu-img.
2046 */
2047
2048 if (virDomainObjIsActive(vm)) {
2049 /* Transitions 4, 7 */
2050 qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT,
2051 QEMU_ASYNC_JOB_START, 0);
2052 virDomainAuditStop(vm, "from-snapshot");
2053 detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
2054 event = virDomainEventLifecycleNewFromObj(vm,
2055 VIR_DOMAIN_EVENT_STOPPED,
2056 detail);
2057 }
2058
2059 if (qemuSnapshotRevertInactive(driver, vm, snap) < 0) {
2060 qemuDomainRemoveInactive(driver, vm);
2061 qemuProcessEndJob(driver, vm);
2062 goto cleanup;
2063 }
2064
2065 if (inactiveConfig) {
2066 virDomainObjAssignDef(vm, &inactiveConfig, false, NULL);
2067 defined = true;
2068 }
2069
2070 if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
2071 VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
2072 /* Flush first event, now do transition 2 or 3 */
2073 bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
2074
2075 start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
2076
2077 virObjectEventStateQueue(driver->domainEventState, event);
2078 rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
2079 QEMU_ASYNC_JOB_START, NULL, -1, NULL, NULL,
2080 VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
2081 start_flags);
2082 virDomainAuditStart(vm, "from-snapshot", rc >= 0);
2083 if (rc < 0) {
2084 qemuDomainRemoveInactive(driver, vm);
2085 qemuProcessEndJob(driver, vm);
2086 goto cleanup;
2087 }
2088 detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
2089 event = virDomainEventLifecycleNewFromObj(vm,
2090 VIR_DOMAIN_EVENT_STARTED,
2091 detail);
2092 if (paused) {
2093 detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
2094 event2 = virDomainEventLifecycleNewFromObj(vm,
2095 VIR_DOMAIN_EVENT_SUSPENDED,
2096 detail);
2097 }
2098 }
2099 break;
2100
2101 case VIR_DOMAIN_SNAPSHOT_PMSUSPENDED:
2102 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2103 _("qemu doesn't support reversion of snapshot taken in "
2104 "PMSUSPENDED state"));
2105 goto endjob;
2106
2107 case VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT:
2108 /* Rejected earlier as an external snapshot */
2109 case VIR_DOMAIN_SNAPSHOT_NOSTATE:
2110 case VIR_DOMAIN_SNAPSHOT_BLOCKED:
2111 case VIR_DOMAIN_SNAPSHOT_LAST:
2112 virReportError(VIR_ERR_INTERNAL_ERROR,
2113 _("Invalid target domain state '%s'. Refusing "
2114 "snapshot reversion"),
2115 virDomainSnapshotStateTypeToString(snapdef->state));
2116 goto endjob;
2117 }
2118
2119 ret = 0;
2120
2121 endjob:
2122 qemuProcessEndJob(driver, vm);
2123
2124 cleanup:
2125 if (ret == 0) {
2126 qemuSnapshotSetCurrent(vm, snap);
2127 if (qemuDomainSnapshotWriteMetadata(vm, snap,
2128 driver->xmlopt,
2129 cfg->snapshotDir) < 0) {
2130 virDomainSnapshotSetCurrent(vm->snapshots, NULL);
2131 ret = -1;
2132 }
2133 }
2134 if (ret == 0 && defined && vm->persistent &&
2135 !(ret = virDomainDefSave(vm->newDef ? vm->newDef : vm->def,
2136 driver->xmlopt, cfg->configDir))) {
2137 detail = VIR_DOMAIN_EVENT_DEFINED_FROM_SNAPSHOT;
2138 virObjectEventStateQueue(driver->domainEventState,
2139 virDomainEventLifecycleNewFromObj(vm,
2140 VIR_DOMAIN_EVENT_DEFINED,
2141 detail));
2142 }
2143 virObjectEventStateQueue(driver->domainEventState, event);
2144 virObjectEventStateQueue(driver->domainEventState, event2);
2145 virCPUDefFree(origCPU);
2146 virDomainDefFree(config);
2147 virDomainDefFree(inactiveConfig);
2148
2149 return ret;
2150 }
2151
2152
2153 typedef struct _virQEMUMomentReparent virQEMUMomentReparent;
2154 struct _virQEMUMomentReparent {
2155 const char *dir;
2156 virDomainMomentObj *parent;
2157 virDomainObj *vm;
2158 virDomainXMLOption *xmlopt;
2159 int err;
2160 int (*writeMetadata)(virDomainObj *, virDomainMomentObj *,
2161 virDomainXMLOption *, const char *);
2162 };
2163
2164
2165 static int
qemuSnapshotChildrenReparent(void * payload,const char * name G_GNUC_UNUSED,void * data)2166 qemuSnapshotChildrenReparent(void *payload,
2167 const char *name G_GNUC_UNUSED,
2168 void *data)
2169 {
2170 virDomainMomentObj *moment = payload;
2171 virQEMUMomentReparent *rep = data;
2172
2173 if (rep->err < 0)
2174 return 0;
2175
2176 VIR_FREE(moment->def->parent_name);
2177
2178 if (rep->parent->def)
2179 moment->def->parent_name = g_strdup(rep->parent->def->name);
2180
2181 rep->err = rep->writeMetadata(rep->vm, moment, rep->xmlopt,
2182 rep->dir);
2183 return 0;
2184 }
2185
2186
2187 int
qemuSnapshotDelete(virDomainObj * vm,virDomainSnapshotPtr snapshot,unsigned int flags)2188 qemuSnapshotDelete(virDomainObj *vm,
2189 virDomainSnapshotPtr snapshot,
2190 unsigned int flags)
2191 {
2192 virQEMUDriver *driver = snapshot->domain->conn->privateData;
2193 int ret = -1;
2194 virDomainMomentObj *snap = NULL;
2195 virQEMUMomentRemove rem;
2196 virQEMUMomentReparent rep;
2197 bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
2198 int external = 0;
2199 g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
2200
2201 virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
2202 VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
2203 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
2204
2205 if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2206 return -1;
2207
2208 if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
2209 goto endjob;
2210
2211 if (!metadata_only) {
2212 if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
2213 virDomainSnapshotIsExternal(snap))
2214 external++;
2215 if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
2216 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY))
2217 virDomainMomentForEachDescendant(snap,
2218 qemuSnapshotCountExternal,
2219 &external);
2220 if (external) {
2221 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2222 _("deletion of %d external disk snapshots not "
2223 "supported yet"), external);
2224 goto endjob;
2225 }
2226 }
2227
2228 if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
2229 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
2230 rem.driver = driver;
2231 rem.vm = vm;
2232 rem.metadata_only = metadata_only;
2233 rem.err = 0;
2234 rem.current = virDomainSnapshotGetCurrent(vm->snapshots);
2235 rem.found = false;
2236 rem.momentDiscard = qemuDomainSnapshotDiscard;
2237 virDomainMomentForEachDescendant(snap, qemuDomainMomentDiscardAll,
2238 &rem);
2239 if (rem.err < 0)
2240 goto endjob;
2241 if (rem.found) {
2242 qemuSnapshotSetCurrent(vm, snap);
2243
2244 if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
2245 if (qemuDomainSnapshotWriteMetadata(vm, snap,
2246 driver->xmlopt,
2247 cfg->snapshotDir) < 0) {
2248 virReportError(VIR_ERR_INTERNAL_ERROR,
2249 _("failed to set snapshot '%s' as current"),
2250 snap->def->name);
2251 virDomainSnapshotSetCurrent(vm->snapshots, NULL);
2252 goto endjob;
2253 }
2254 }
2255 }
2256 } else if (snap->nchildren) {
2257 rep.dir = cfg->snapshotDir;
2258 rep.parent = snap->parent;
2259 rep.vm = vm;
2260 rep.err = 0;
2261 rep.xmlopt = driver->xmlopt;
2262 rep.writeMetadata = qemuDomainSnapshotWriteMetadata;
2263 virDomainMomentForEachChild(snap,
2264 qemuSnapshotChildrenReparent,
2265 &rep);
2266 if (rep.err < 0)
2267 goto endjob;
2268 virDomainMomentMoveChildren(snap, snap->parent);
2269 }
2270
2271 if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
2272 virDomainMomentDropChildren(snap);
2273 ret = 0;
2274 } else {
2275 ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
2276 }
2277
2278 endjob:
2279 qemuDomainObjEndJob(driver, vm);
2280
2281 return ret;
2282 }
2283