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