1 /*
2  * qemu_checkpoint.c: checkpoint 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 <sys/types.h>
22 
23 #include "qemu_checkpoint.h"
24 #include "qemu_capabilities.h"
25 #include "qemu_monitor.h"
26 #include "qemu_domain.h"
27 #include "qemu_block.h"
28 
29 #include "virerror.h"
30 #include "virlog.h"
31 #include "datatypes.h"
32 #include "viralloc.h"
33 #include "domain_conf.h"
34 #include "libvirt_internal.h"
35 #include "virxml.h"
36 #include "virstring.h"
37 #include "virdomaincheckpointobjlist.h"
38 #include "virdomainsnapshotobjlist.h"
39 
40 #define VIR_FROM_THIS VIR_FROM_QEMU
41 
42 VIR_LOG_INIT("qemu.qemu_checkpoint");
43 
44 /**
45  * qemuCheckpointSetCurrent: Set currently active checkpoint
46  *
47  * @vm: domain object
48  * @newcurrent: checkpoint object to set as current/active
49  *
50  * Sets @newcurrent as the 'current' checkpoint of @vm. This helper ensures that
51  * the checkpoint which was 'current' previously is updated.
52  */
53 static void
qemuCheckpointSetCurrent(virDomainObj * vm,virDomainMomentObj * newcurrent)54 qemuCheckpointSetCurrent(virDomainObj *vm,
55                        virDomainMomentObj *newcurrent)
56 {
57     qemuDomainObjPrivate *priv = vm->privateData;
58     virQEMUDriver *driver = priv->driver;
59     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
60     virDomainMomentObj *oldcurrent = virDomainCheckpointGetCurrent(vm->checkpoints);
61 
62     virDomainCheckpointSetCurrent(vm->checkpoints, newcurrent);
63 
64     /* we need to write out metadata for the old checkpoint to update the
65      * 'active' property */
66     if (oldcurrent &&
67         oldcurrent != newcurrent) {
68         if (qemuCheckpointWriteMetadata(vm, oldcurrent, driver->xmlopt, cfg->checkpointDir) < 0)
69             VIR_WARN("failed to update old current checkpoint");
70     }
71 }
72 
73 
74 /* Looks up the domain object from checkpoint and unlocks the
75  * driver. The returned domain object is locked and ref'd and the
76  * caller must call virDomainObjEndAPI() on it. */
77 virDomainObj *
qemuDomObjFromCheckpoint(virDomainCheckpointPtr checkpoint)78 qemuDomObjFromCheckpoint(virDomainCheckpointPtr checkpoint)
79 {
80     return qemuDomainObjFromDomain(checkpoint->domain);
81 }
82 
83 
84 /* Looks up checkpoint object from VM and name */
85 virDomainMomentObj *
qemuCheckpointObjFromName(virDomainObj * vm,const char * name)86 qemuCheckpointObjFromName(virDomainObj *vm,
87                           const char *name)
88 {
89     virDomainMomentObj *chk = NULL;
90     chk = virDomainCheckpointFindByName(vm->checkpoints, name);
91     if (!chk)
92         virReportError(VIR_ERR_NO_DOMAIN_CHECKPOINT,
93                        _("no domain checkpoint with matching name '%s'"),
94                        name);
95 
96     return chk;
97 }
98 
99 
100 /* Looks up checkpoint object from VM and checkpointPtr */
101 virDomainMomentObj *
qemuCheckpointObjFromCheckpoint(virDomainObj * vm,virDomainCheckpointPtr checkpoint)102 qemuCheckpointObjFromCheckpoint(virDomainObj *vm,
103                                 virDomainCheckpointPtr checkpoint)
104 {
105     return qemuCheckpointObjFromName(vm, checkpoint->name);
106 }
107 
108 
109 int
qemuCheckpointWriteMetadata(virDomainObj * vm,virDomainMomentObj * checkpoint,virDomainXMLOption * xmlopt,const char * checkpointDir)110 qemuCheckpointWriteMetadata(virDomainObj *vm,
111                             virDomainMomentObj *checkpoint,
112                             virDomainXMLOption *xmlopt,
113                             const char *checkpointDir)
114 {
115     unsigned int flags = VIR_DOMAIN_CHECKPOINT_FORMAT_SECURE;
116     virDomainCheckpointDef *def = virDomainCheckpointObjGetDef(checkpoint);
117     g_autofree char *newxml = NULL;
118     g_autofree char *chkDir = NULL;
119     g_autofree char *chkFile = NULL;
120 
121     newxml = virDomainCheckpointDefFormat(def, xmlopt, flags);
122     if (newxml == NULL)
123         return -1;
124 
125     chkDir = g_strdup_printf("%s/%s", checkpointDir, vm->def->name);
126     if (g_mkdir_with_parents(chkDir, 0777) < 0) {
127         virReportSystemError(errno, _("cannot create checkpoint directory '%s'"),
128                              chkDir);
129         return -1;
130     }
131 
132     chkFile = g_strdup_printf("%s/%s.xml", chkDir, def->parent.name);
133 
134     return virXMLSaveFile(chkFile, NULL, "checkpoint-edit", newxml);
135 }
136 
137 
138 int
qemuCheckpointDiscardDiskBitmaps(virStorageSource * src,GHashTable * blockNamedNodeData,const char * delbitmap,virJSONValue * actions,const char * diskdst,GSList ** reopenimages)139 qemuCheckpointDiscardDiskBitmaps(virStorageSource *src,
140                                  GHashTable *blockNamedNodeData,
141                                  const char *delbitmap,
142                                  virJSONValue *actions,
143                                  const char *diskdst,
144                                  GSList **reopenimages)
145 {
146     virStorageSource *n;
147     bool found = false;
148 
149     /* find the backing chain entry with bitmap named '@delbitmap' */
150     for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
151         qemuBlockNamedNodeDataBitmap *bitmapdata;
152 
153         if (!(bitmapdata = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
154                                                                  n, delbitmap)))
155             continue;
156 
157         found = true;
158 
159         if (qemuMonitorTransactionBitmapRemove(actions,
160                                                n->nodeformat,
161                                                bitmapdata->name) < 0)
162             return -1;
163 
164         if (n != src)
165             *reopenimages = g_slist_prepend(*reopenimages, n);
166     }
167 
168     if (!found) {
169         virReportError(VIR_ERR_INTERNAL_ERROR,
170                        _("bitmap '%s' not found in backing chain of '%s'"),
171                        delbitmap, diskdst);
172         return -1;
173     }
174 
175     return 0;
176 }
177 
178 
179 static int
qemuCheckpointDiscardBitmaps(virDomainObj * vm,virDomainCheckpointDef * chkdef)180 qemuCheckpointDiscardBitmaps(virDomainObj *vm,
181                              virDomainCheckpointDef *chkdef)
182 {
183     qemuDomainObjPrivate *priv = vm->privateData;
184     virQEMUDriver *driver = priv->driver;
185     g_autoptr(GHashTable) blockNamedNodeData = NULL;
186     int rc = -1;
187     g_autoptr(virJSONValue) actions = NULL;
188     size_t i;
189     g_autoptr(GSList) reopenimages = NULL;
190     g_autoptr(GSList) relabelimages = NULL;
191     GSList *next;
192 
193     actions = virJSONValueNewArray();
194 
195     if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
196         return -1;
197 
198     for (i = 0; i < chkdef->ndisks; i++) {
199         virDomainCheckpointDiskDef *chkdisk = &chkdef->disks[i];
200         virDomainDiskDef *domdisk = virDomainDiskByTarget(vm->def, chkdisk->name);
201 
202         /* domdisk can be missing e.g. when it was unplugged */
203         if (!domdisk)
204             continue;
205 
206         if (chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
207             continue;
208 
209         if (!chkdisk->bitmap) {
210             virReportError(VIR_ERR_INVALID_ARG,
211                            _("missing bitmap name for disk '%s' of checkpoint '%s'"),
212                            chkdisk->name, chkdef->parent.name);
213             return -1;
214         }
215 
216         if (qemuCheckpointDiscardDiskBitmaps(domdisk->src, blockNamedNodeData,
217                                              chkdisk->bitmap,
218                                              actions, domdisk->dst,
219                                              &reopenimages) < 0)
220             return -1;
221     }
222 
223     /* label any non-top images for read-write access */
224     for (next = reopenimages; next; next = next->next) {
225         virStorageSource *src = next->data;
226 
227         if (qemuDomainStorageSourceAccessAllow(driver, vm, src,
228                                                false, false, false) < 0)
229             goto relabel;
230 
231         if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN) &&
232             qemuBlockReopenReadWrite(vm, src, QEMU_ASYNC_JOB_NONE) < 0)
233             goto relabel;
234 
235         relabelimages = g_slist_prepend(relabelimages, src);
236     }
237 
238     qemuDomainObjEnterMonitor(driver, vm);
239     rc = qemuMonitorTransaction(priv->mon, &actions);
240     if (qemuDomainObjExitMonitor(driver, vm) < 0)
241         return -1;
242 
243  relabel:
244     for (next = relabelimages; next; next = next->next) {
245         virStorageSource *src = next->data;
246 
247         if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN))
248             ignore_value(qemuBlockReopenReadOnly(vm, src, QEMU_ASYNC_JOB_NONE));
249 
250         ignore_value(qemuDomainStorageSourceAccessAllow(driver, vm, src,
251                                                         true, false, false));
252     }
253 
254     return rc;
255 }
256 
257 
258 static int
qemuCheckpointDiscard(virQEMUDriver * driver,virDomainObj * vm,virDomainMomentObj * chk,bool update_parent,bool metadata_only)259 qemuCheckpointDiscard(virQEMUDriver *driver,
260                       virDomainObj *vm,
261                       virDomainMomentObj *chk,
262                       bool update_parent,
263                       bool metadata_only)
264 {
265     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
266     g_autofree char *chkFile = NULL;
267     bool chkcurrent = chk == virDomainCheckpointGetCurrent(vm->checkpoints);
268 
269     if (!metadata_only && !virDomainObjIsActive(vm)) {
270         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
271                        _("cannot remove checkpoint from inactive domain"));
272         return -1;
273     }
274 
275     chkFile = g_strdup_printf("%s/%s/%s.xml", cfg->checkpointDir, vm->def->name,
276                               chk->def->name);
277 
278     if (!metadata_only) {
279         virDomainCheckpointDef *chkdef = virDomainCheckpointObjGetDef(chk);
280         if (qemuCheckpointDiscardBitmaps(vm, chkdef) < 0)
281             return -1;
282     }
283 
284     if (chkcurrent) {
285         virDomainMomentObj *parent = NULL;
286 
287         virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
288         parent = virDomainCheckpointFindByName(vm->checkpoints,
289                                                chk->def->parent_name);
290 
291         if (update_parent && parent) {
292             virDomainCheckpointSetCurrent(vm->checkpoints, parent);
293             if (qemuCheckpointWriteMetadata(vm, parent,
294                                             driver->xmlopt,
295                                             cfg->checkpointDir) < 0) {
296                 VIR_WARN("failed to set parent checkpoint '%s' as current",
297                          chk->def->parent_name);
298                 virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
299             }
300         }
301     }
302 
303     if (unlink(chkFile) < 0)
304         VIR_WARN("Failed to unlink %s", chkFile);
305     if (update_parent)
306         virDomainMomentDropParent(chk);
307     virDomainCheckpointObjListRemove(vm->checkpoints, chk);
308 
309     return 0;
310 }
311 
312 
313 int
qemuCheckpointDiscardAllMetadata(virQEMUDriver * driver,virDomainObj * vm)314 qemuCheckpointDiscardAllMetadata(virQEMUDriver *driver,
315                                        virDomainObj *vm)
316 {
317     virQEMUMomentRemove rem = {
318         .driver = driver,
319         .vm = vm,
320         .metadata_only = true,
321         .momentDiscard = qemuCheckpointDiscard,
322     };
323 
324     virDomainCheckpointForEach(vm->checkpoints, qemuDomainMomentDiscardAll,
325                                &rem);
326     virDomainCheckpointObjListRemoveAll(vm->checkpoints);
327 
328     return rem.err;
329 }
330 
331 
332 /* Called inside job lock */
333 static int
qemuCheckpointPrepare(virQEMUDriver * driver,virDomainObj * vm,virDomainCheckpointDef * def)334 qemuCheckpointPrepare(virQEMUDriver *driver,
335                       virDomainObj *vm,
336                       virDomainCheckpointDef *def)
337 {
338     size_t i;
339     g_autofree char *xml = NULL;
340     qemuDomainObjPrivate *priv = vm->privateData;
341 
342     /* Easiest way to clone inactive portion of vm->def is via
343      * conversion in and back out of xml.  */
344     if (!(xml = qemuDomainDefFormatLive(driver, priv->qemuCaps,
345                                         vm->def, priv->origCPU,
346                                         true, true)) ||
347         !(def->parent.dom = virDomainDefParseString(xml, driver->xmlopt,
348                                                     priv->qemuCaps,
349                                                     VIR_DOMAIN_DEF_PARSE_INACTIVE |
350                                                     VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
351         return -1;
352 
353     if (virDomainCheckpointAlignDisks(def) < 0)
354         return -1;
355 
356     for (i = 0; i < def->ndisks; i++) {
357         virDomainCheckpointDiskDef *disk = &def->disks[i];
358 
359         if (disk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
360             continue;
361 
362         if (STRNEQ(disk->bitmap, def->parent.name)) {
363             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
364                            _("bitmap for disk '%s' must match checkpoint name '%s'"),
365                            disk->name, def->parent.name);
366             return -1;
367         }
368 
369         if (vm->def->disks[i]->src->format != VIR_STORAGE_FILE_QCOW2) {
370             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
371                            _("checkpoint for disk %s unsupported "
372                              "for storage type %s"),
373                            disk->name,
374                            virStorageFileFormatTypeToString(
375                                vm->def->disks[i]->src->format));
376             return -1;
377         }
378 
379         if (!qemuDomainDiskBlockJobIsSupported(vm, vm->def->disks[i]))
380             return -1;
381     }
382 
383     return 0;
384 }
385 
386 static int
qemuCheckpointAddActions(virDomainObj * vm,virJSONValue * actions,virDomainCheckpointDef * def)387 qemuCheckpointAddActions(virDomainObj *vm,
388                          virJSONValue *actions,
389                          virDomainCheckpointDef *def)
390 {
391     size_t i;
392 
393     for (i = 0; i < def->ndisks; i++) {
394         virDomainCheckpointDiskDef *chkdisk = &def->disks[i];
395         virDomainDiskDef *domdisk = virDomainDiskByTarget(vm->def, chkdisk->name);
396 
397         /* checkpoint definition validator mandates that the corresponding
398          * domdisk should exist */
399         if (!domdisk ||
400             chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
401             continue;
402 
403         if (qemuMonitorTransactionBitmapAdd(actions, domdisk->src->nodeformat,
404                                             chkdisk->bitmap, true, false, 0) < 0)
405             return -1;
406     }
407     return 0;
408 }
409 
410 
411 static int
qemuCheckpointRedefineValidateBitmaps(virDomainObj * vm,virDomainCheckpointDef * chkdef)412 qemuCheckpointRedefineValidateBitmaps(virDomainObj *vm,
413                                       virDomainCheckpointDef *chkdef)
414 {
415     g_autoptr(GHashTable) blockNamedNodeData = NULL;
416     size_t i;
417 
418     if (virDomainObjCheckActive(vm) < 0)
419         return -1;
420 
421     if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
422         return -1;
423 
424     for (i = 0; i < chkdef->ndisks; i++) {
425         virDomainCheckpointDiskDef *chkdisk = chkdef->disks + i;
426         virDomainDiskDef *domdisk;
427 
428         if (chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
429             continue;
430 
431         /* we tolerate missing disks due to possible detach */
432         if (!(domdisk = virDomainDiskByTarget(vm->def, chkdisk->name)))
433             continue;
434 
435         if (!qemuBlockBitmapChainIsValid(domdisk->src, chkdef->parent.name,
436                                          blockNamedNodeData)) {
437             virReportError(VIR_ERR_CHECKPOINT_INCONSISTENT,
438                            _("missing or broken bitmap '%s' for disk '%s'"),
439                            chkdef->parent.name, domdisk->dst);
440             return -1;
441         }
442     }
443 
444     return 0;
445 }
446 
447 
448 static virDomainMomentObj *
qemuCheckpointRedefine(virDomainObj * vm,virDomainCheckpointDef ** def,bool * update_current,bool validate_bitmaps)449 qemuCheckpointRedefine(virDomainObj *vm,
450                        virDomainCheckpointDef **def,
451                        bool *update_current,
452                        bool validate_bitmaps)
453 {
454     if (virDomainCheckpointRedefinePrep(vm, *def, update_current) < 0)
455         return NULL;
456 
457     if (validate_bitmaps &&
458         qemuCheckpointRedefineValidateBitmaps(vm, *def) < 0)
459         return NULL;
460 
461     return virDomainCheckpointRedefineCommit(vm, def);
462 }
463 
464 
465 int
qemuCheckpointCreateCommon(virQEMUDriver * driver,virDomainObj * vm,virDomainCheckpointDef ** def,virJSONValue ** actions,virDomainMomentObj ** chk)466 qemuCheckpointCreateCommon(virQEMUDriver *driver,
467                            virDomainObj *vm,
468                            virDomainCheckpointDef **def,
469                            virJSONValue **actions,
470                            virDomainMomentObj **chk)
471 {
472     g_autoptr(virJSONValue) tmpactions = NULL;
473     virDomainMomentObj *parent;
474 
475     if (qemuCheckpointPrepare(driver, vm, *def) < 0)
476         return -1;
477 
478     if ((parent = virDomainCheckpointGetCurrent(vm->checkpoints)))
479         (*def)->parent.parent_name = g_strdup(parent->def->name);
480 
481     tmpactions = virJSONValueNewArray();
482 
483     if (qemuCheckpointAddActions(vm, tmpactions, *def) < 0)
484         return -1;
485 
486     if (!(*chk = virDomainCheckpointAssignDef(vm->checkpoints, *def)))
487         return -1;
488 
489     *def = NULL;
490 
491     *actions = g_steal_pointer(&tmpactions);
492     return 0;
493 }
494 
495 
496 /**
497  * qemuCheckpointRollbackMetadata:
498  * @vm: domain object
499  * @chk: checkpoint object
500  *
501  * If @chk is not null remove the @chk object from the list of checkpoints of @vm.
502  */
503 void
qemuCheckpointRollbackMetadata(virDomainObj * vm,virDomainMomentObj * chk)504 qemuCheckpointRollbackMetadata(virDomainObj *vm,
505                                virDomainMomentObj *chk)
506 {
507     if (!chk)
508         return;
509 
510     virDomainCheckpointObjListRemove(vm->checkpoints, chk);
511 }
512 
513 
514 static virDomainMomentObj *
qemuCheckpointCreate(virQEMUDriver * driver,virDomainObj * vm,virDomainCheckpointDef ** def)515 qemuCheckpointCreate(virQEMUDriver *driver,
516                      virDomainObj *vm,
517                      virDomainCheckpointDef **def)
518 {
519     g_autoptr(virJSONValue) actions = NULL;
520     virDomainMomentObj *chk = NULL;
521     int rc;
522 
523     if (qemuCheckpointCreateCommon(driver, vm, def, &actions, &chk) < 0)
524         return NULL;
525 
526     qemuDomainObjEnterMonitor(driver, vm);
527     rc = qemuMonitorTransaction(qemuDomainGetMonitor(vm), &actions);
528     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0) {
529         qemuCheckpointRollbackMetadata(vm, chk);
530         return NULL;
531     }
532 
533     return chk;
534 }
535 
536 
537 int
qemuCheckpointCreateFinalize(virQEMUDriver * driver,virDomainObj * vm,virQEMUDriverConfig * cfg,virDomainMomentObj * chk,bool update_current)538 qemuCheckpointCreateFinalize(virQEMUDriver *driver,
539                              virDomainObj *vm,
540                              virQEMUDriverConfig *cfg,
541                              virDomainMomentObj *chk,
542                              bool update_current)
543 {
544     if (update_current)
545         qemuCheckpointSetCurrent(vm, chk);
546 
547     if (qemuCheckpointWriteMetadata(vm, chk,
548                                     driver->xmlopt,
549                                     cfg->checkpointDir) < 0) {
550         /* if writing of metadata fails, error out rather than trying
551          * to silently carry on without completing the checkpoint */
552         virReportError(VIR_ERR_INTERNAL_ERROR,
553                        _("unable to save metadata for checkpoint %s"),
554                        chk->def->name);
555         qemuCheckpointRollbackMetadata(vm, chk);
556         return -1;
557     }
558 
559     virDomainCheckpointLinkParent(vm->checkpoints, chk);
560 
561     return 0;
562 }
563 
564 
565 virDomainCheckpointPtr
qemuCheckpointCreateXML(virDomainPtr domain,virDomainObj * vm,const char * xmlDesc,unsigned int flags)566 qemuCheckpointCreateXML(virDomainPtr domain,
567                         virDomainObj *vm,
568                         const char *xmlDesc,
569                         unsigned int flags)
570 {
571     qemuDomainObjPrivate *priv = vm->privateData;
572     virQEMUDriver *driver = priv->driver;
573     virDomainMomentObj *chk = NULL;
574     virDomainCheckpointPtr checkpoint = NULL;
575     bool update_current = true;
576     bool redefine = flags & VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE;
577     bool validate_bitmaps = flags & VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE_VALIDATE;
578     unsigned int parse_flags = 0;
579     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
580     g_autoptr(virDomainCheckpointDef) def = NULL;
581 
582     virCheckFlags(VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE |
583                   VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE_VALIDATE, NULL);
584 
585     if (redefine) {
586         parse_flags |= VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE;
587         update_current = false;
588     }
589 
590     if (!redefine) {
591         if (!virDomainObjIsActive(vm)) {
592             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
593                            _("cannot create checkpoint for inactive domain"));
594             return NULL;
595         }
596 
597         if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP)) {
598             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
599                            _("incremental backup is not supported yet"));
600             return NULL;
601         }
602     }
603 
604     if (!(def = virDomainCheckpointDefParseString(xmlDesc, driver->xmlopt,
605                                                   priv->qemuCaps, parse_flags)))
606         return NULL;
607     /* Unlike snapshots, the RNG schema already ensured a sane filename. */
608 
609     /* We are going to modify the domain below. */
610     if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
611         return NULL;
612 
613     if (redefine) {
614         chk = qemuCheckpointRedefine(vm, &def, &update_current, validate_bitmaps);
615     } else {
616         chk = qemuCheckpointCreate(driver, vm, &def);
617     }
618 
619     if (!chk)
620         goto endjob;
621 
622     if (qemuCheckpointCreateFinalize(driver, vm, cfg, chk, update_current) < 0)
623         goto endjob;
624 
625     /* If we fail after this point, there's not a whole lot we can do;
626      * we've successfully created the checkpoint, so we have to go
627      * forward the best we can.
628      */
629     checkpoint = virGetDomainCheckpoint(domain, chk->def->name);
630 
631  endjob:
632     qemuDomainObjEndJob(driver, vm);
633 
634     return checkpoint;
635 }
636 
637 
638 struct qemuCheckpointDiskMap {
639     virDomainCheckpointDiskDef *chkdisk;
640     virDomainDiskDef *domdisk;
641 };
642 
643 
644 static int
qemuCheckpointGetXMLDescUpdateSize(virDomainObj * vm,virDomainCheckpointDef * chkdef)645 qemuCheckpointGetXMLDescUpdateSize(virDomainObj *vm,
646                                    virDomainCheckpointDef *chkdef)
647 {
648     qemuDomainObjPrivate *priv = vm->privateData;
649     virQEMUDriver *driver = priv->driver;
650     g_autoptr(GHashTable) blockNamedNodeData = NULL;
651     g_autofree struct qemuCheckpointDiskMap *diskmap = NULL;
652     g_autoptr(virJSONValue) recoveractions = NULL;
653     g_autoptr(virJSONValue) mergeactions = virJSONValueNewArray();
654     g_autoptr(virJSONValue) cleanupactions = virJSONValueNewArray();
655     int rc = 0;
656     size_t ndisks = 0;
657     size_t i;
658     int ret = -1;
659 
660     if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
661         return -1;
662 
663     if (virDomainObjCheckActive(vm) < 0)
664         goto endjob;
665 
666     if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
667         goto endjob;
668 
669     /* enumerate disks relevant for the checkpoint which are also present in the
670      * domain */
671     diskmap = g_new0(struct qemuCheckpointDiskMap, chkdef->ndisks);
672 
673     for (i = 0; i < chkdef->ndisks; i++) {
674         virDomainCheckpointDiskDef *chkdisk = chkdef->disks + i;
675         virDomainDiskDef *domdisk;
676 
677         chkdisk->size = 0;
678         chkdisk->sizeValid = false;
679 
680         if (chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
681             continue;
682 
683         if (!(domdisk = virDomainDiskByTarget(vm->def, chkdisk->name)))
684             continue;
685 
686         if (!qemuBlockBitmapChainIsValid(domdisk->src, chkdef->parent.name, blockNamedNodeData))
687             continue;
688 
689         diskmap[ndisks].chkdisk = chkdisk;
690         diskmap[ndisks].domdisk = domdisk;
691         ndisks++;
692     }
693 
694     if (ndisks == 0) {
695         ret = 0;
696         goto endjob;
697     }
698 
699     /* we need to calculate the merged bitmap to obtain accurate data */
700     for (i = 0; i < ndisks; i++) {
701         virDomainDiskDef *domdisk = diskmap[i].domdisk;
702         g_autoptr(virJSONValue) actions = NULL;
703 
704         /* possibly delete leftovers from previous cases */
705         if (qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, domdisk->src,
706                                                   "libvirt-tmp-size-xml")) {
707             if (!recoveractions)
708                 recoveractions = virJSONValueNewArray();
709 
710             if (qemuMonitorTransactionBitmapRemove(recoveractions,
711                                                    domdisk->src->nodeformat,
712                                                    "libvirt-tmp-size-xml") < 0)
713                 goto endjob;
714         }
715 
716         if (qemuBlockGetBitmapMergeActions(domdisk->src, NULL, domdisk->src,
717                                            chkdef->parent.name, "libvirt-tmp-size-xml",
718                                            NULL, &actions, blockNamedNodeData) < 0)
719             goto endjob;
720 
721         if (virJSONValueArrayConcat(mergeactions, actions) < 0)
722             goto endjob;
723 
724         if (qemuMonitorTransactionBitmapRemove(cleanupactions,
725                                                domdisk->src->nodeformat,
726                                                "libvirt-tmp-size-xml") < 0)
727             goto endjob;
728     }
729 
730     qemuDomainObjEnterMonitor(driver, vm);
731 
732     if (rc == 0 && recoveractions)
733         rc = qemuMonitorTransaction(priv->mon, &recoveractions);
734 
735     if (rc == 0)
736         rc = qemuMonitorTransaction(priv->mon, &mergeactions);
737 
738     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
739         goto endjob;
740 
741     /* now do a final refresh */
742     virHashFree(blockNamedNodeData);
743     if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
744         goto endjob;
745 
746     qemuDomainObjEnterMonitor(driver, vm);
747 
748     rc = qemuMonitorTransaction(priv->mon, &cleanupactions);
749 
750     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
751         goto endjob;
752 
753     /* update disks */
754     for (i = 0; i < ndisks; i++) {
755         virDomainCheckpointDiskDef *chkdisk = diskmap[i].chkdisk;
756         virDomainDiskDef *domdisk = diskmap[i].domdisk;
757         qemuBlockNamedNodeDataBitmap *bitmap;
758 
759         if ((bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, domdisk->src,
760                                                             "libvirt-tmp-size-xml"))) {
761             chkdisk->size = bitmap->dirtybytes;
762             chkdisk->sizeValid = true;
763         }
764     }
765 
766     ret = 0;
767 
768  endjob:
769     qemuDomainObjEndJob(driver, vm);
770     return ret;
771 }
772 
773 
774 char *
qemuCheckpointGetXMLDesc(virDomainObj * vm,virDomainCheckpointPtr checkpoint,unsigned int flags)775 qemuCheckpointGetXMLDesc(virDomainObj *vm,
776                          virDomainCheckpointPtr checkpoint,
777                          unsigned int flags)
778 {
779     qemuDomainObjPrivate *priv = vm->privateData;
780     virQEMUDriver *driver = priv->driver;
781     virDomainMomentObj *chk = NULL;
782     virDomainCheckpointDef *chkdef;
783     unsigned int format_flags;
784 
785     virCheckFlags(VIR_DOMAIN_CHECKPOINT_XML_SECURE |
786                   VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN |
787                   VIR_DOMAIN_CHECKPOINT_XML_SIZE, NULL);
788 
789     if (!(chk = qemuCheckpointObjFromCheckpoint(vm, checkpoint)))
790         return NULL;
791 
792     chkdef = virDomainCheckpointObjGetDef(chk);
793 
794     if (flags & VIR_DOMAIN_CHECKPOINT_XML_SIZE &&
795         qemuCheckpointGetXMLDescUpdateSize(vm, chkdef) < 0)
796         return NULL;
797 
798     format_flags = virDomainCheckpointFormatConvertXMLFlags(flags);
799     return virDomainCheckpointDefFormat(chkdef, driver->xmlopt,
800                                         format_flags);
801 }
802 
803 
804 struct virQEMUCheckpointReparent {
805     const char *dir;
806     virDomainMomentObj *parent;
807     virDomainObj *vm;
808     virDomainXMLOption *xmlopt;
809     int err;
810 };
811 
812 
813 static int
qemuCheckpointReparentChildren(void * payload,const char * name G_GNUC_UNUSED,void * data)814 qemuCheckpointReparentChildren(void *payload,
815                                const char *name G_GNUC_UNUSED,
816                                void *data)
817 {
818     virDomainMomentObj *moment = payload;
819     struct virQEMUCheckpointReparent *rep = data;
820 
821     if (rep->err < 0)
822         return 0;
823 
824     VIR_FREE(moment->def->parent_name);
825 
826     if (rep->parent->def)
827         moment->def->parent_name = g_strdup(rep->parent->def->name);
828 
829     rep->err = qemuCheckpointWriteMetadata(rep->vm, moment,
830                                            rep->xmlopt, rep->dir);
831     return 0;
832 }
833 
834 
835 int
qemuCheckpointDelete(virDomainObj * vm,virDomainCheckpointPtr checkpoint,unsigned int flags)836 qemuCheckpointDelete(virDomainObj *vm,
837                      virDomainCheckpointPtr checkpoint,
838                      unsigned int flags)
839 {
840     qemuDomainObjPrivate *priv = vm->privateData;
841     virQEMUDriver *driver = priv->driver;
842     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
843     int ret = -1;
844     virDomainMomentObj *chk = NULL;
845     virQEMUMomentRemove rem;
846     struct virQEMUCheckpointReparent rep;
847     bool metadata_only = !!(flags & VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY);
848 
849     virCheckFlags(VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN |
850                   VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY |
851                   VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY, -1);
852 
853     if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
854         return -1;
855 
856     if (!metadata_only) {
857         if (!virDomainObjIsActive(vm)) {
858             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
859                            _("cannot delete checkpoint for inactive domain"));
860             goto endjob;
861         }
862 
863         if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP)) {
864             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
865                            _("incremental backup is not supported yet"));
866             goto endjob;
867         }
868     }
869 
870     if (!(chk = qemuCheckpointObjFromCheckpoint(vm, checkpoint)))
871         goto endjob;
872 
873     if (flags & (VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN |
874                  VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY)) {
875         rem.driver = driver;
876         rem.vm = vm;
877         rem.metadata_only = metadata_only;
878         rem.err = 0;
879         rem.current = virDomainCheckpointGetCurrent(vm->checkpoints);
880         rem.found = false;
881         rem.momentDiscard = qemuCheckpointDiscard;
882         virDomainMomentForEachDescendant(chk, qemuDomainMomentDiscardAll,
883                                          &rem);
884         if (rem.err < 0)
885             goto endjob;
886         if (rem.found) {
887             qemuCheckpointSetCurrent(vm, chk);
888 
889             if (flags & VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY) {
890                 if (qemuCheckpointWriteMetadata(vm, chk,
891                                                 driver->xmlopt,
892                                                 cfg->checkpointDir) < 0) {
893                     virReportError(VIR_ERR_INTERNAL_ERROR,
894                                    _("failed to set checkpoint '%s' as current"),
895                                    chk->def->name);
896                     virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
897                     goto endjob;
898                 }
899             }
900         }
901     } else if (chk->nchildren) {
902         rep.dir = cfg->checkpointDir;
903         rep.parent = chk->parent;
904         rep.vm = vm;
905         rep.err = 0;
906         rep.xmlopt = driver->xmlopt;
907         virDomainMomentForEachChild(chk, qemuCheckpointReparentChildren,
908                                     &rep);
909         if (rep.err < 0)
910             goto endjob;
911         virDomainMomentMoveChildren(chk, chk->parent);
912     }
913 
914     if (flags & VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY) {
915         virDomainMomentDropChildren(chk);
916         ret = 0;
917     } else {
918         ret = qemuCheckpointDiscard(driver, vm, chk, true, metadata_only);
919     }
920 
921  endjob:
922     qemuDomainObjEndJob(driver, vm);
923     return ret;
924 }
925