1 /*
2  * qemu_backup.c: Implementation and handling of the backup jobs
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_alias.h"
22 #include "qemu_block.h"
23 #include "qemu_conf.h"
24 #include "qemu_capabilities.h"
25 #include "qemu_monitor.h"
26 #include "qemu_process.h"
27 #include "qemu_backup.h"
28 #include "qemu_monitor_json.h"
29 #include "qemu_checkpoint.h"
30 #include "qemu_command.h"
31 #include "qemu_security.h"
32 
33 #include "storage_source.h"
34 #include "storage_source_conf.h"
35 #include "virerror.h"
36 #include "virlog.h"
37 #include "virbuffer.h"
38 #include "viralloc.h"
39 #include "virxml.h"
40 #include "virstring.h"
41 #include "backup_conf.h"
42 #include "virdomaincheckpointobjlist.h"
43 
44 #define VIR_FROM_THIS VIR_FROM_QEMU
45 
46 VIR_LOG_INIT("qemu.qemu_backup");
47 
48 
49 static virDomainBackupDef *
qemuDomainGetBackup(virDomainObj * vm)50 qemuDomainGetBackup(virDomainObj *vm)
51 {
52     qemuDomainObjPrivate *priv = vm->privateData;
53 
54     if (!priv->backup) {
55         virReportError(VIR_ERR_NO_DOMAIN_BACKUP, "%s",
56                        _("no domain backup job present"));
57         return NULL;
58     }
59 
60     return priv->backup;
61 }
62 
63 
64 static int
qemuBackupPrepare(virDomainBackupDef * def)65 qemuBackupPrepare(virDomainBackupDef *def)
66 {
67 
68     if (def->type == VIR_DOMAIN_BACKUP_TYPE_PULL) {
69         if (!def->server) {
70             def->server = g_new0(virStorageNetHostDef, 1);
71 
72             def->server->transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
73             def->server->name = g_strdup("localhost");
74         }
75 
76         switch ((virStorageNetHostTransport) def->server->transport) {
77         case VIR_STORAGE_NET_HOST_TRANS_TCP:
78             /* TODO: Update qemu.conf to provide a port range,
79              * probably starting at 10809, for obtaining automatic
80              * port via virPortAllocatorAcquire, as well as store
81              * somewhere if we need to call virPortAllocatorRelease
82              * during BackupEnd. Until then, user must provide port */
83             if (!def->server->port) {
84                 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
85                                _("<domainbackup> must specify TCP port for now"));
86                 return -1;
87             }
88             break;
89 
90         case VIR_STORAGE_NET_HOST_TRANS_UNIX:
91             /* TODO: Do we need to mess with selinux? */
92             break;
93 
94         case VIR_STORAGE_NET_HOST_TRANS_RDMA:
95         case VIR_STORAGE_NET_HOST_TRANS_LAST:
96             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
97                            _("unexpected transport in <domainbackup>"));
98             return -1;
99         }
100     }
101 
102     return 0;
103 }
104 
105 
106 struct qemuBackupDiskData {
107     virDomainBackupDiskDef *backupdisk;
108     virDomainDiskDef *domdisk;
109     qemuBlockJobData *blockjob;
110     virStorageSource *store;
111     virStorageSource *terminator;
112     virStorageSource *backingStore;
113     char *incrementalBitmap;
114     const char *domdiskIncrementalBitmap; /* name of temporary bitmap installed on disk source */
115     qemuBlockStorageSourceChainData *crdata;
116     bool labelled;
117     bool initialized;
118     bool created;
119     bool added;
120     bool started;
121     bool done;
122 };
123 
124 
125 static void
qemuBackupDiskDataCleanupOne(virDomainObj * vm,struct qemuBackupDiskData * dd)126 qemuBackupDiskDataCleanupOne(virDomainObj *vm,
127                              struct qemuBackupDiskData *dd)
128 {
129     qemuDomainObjPrivate *priv = vm->privateData;
130 
131     if (!dd->started) {
132         if (dd->added) {
133             qemuDomainObjEnterMonitor(priv->driver, vm);
134             qemuBlockStorageSourceAttachRollback(priv->mon, dd->crdata->srcdata[0]);
135             ignore_value(qemuDomainObjExitMonitor(priv->driver, vm));
136         }
137 
138         if (dd->created) {
139             if (virStorageSourceUnlink(dd->store) < 0)
140                 VIR_WARN("Unable to remove just-created %s", NULLSTR(dd->store->path));
141         }
142 
143         if (dd->labelled)
144             qemuDomainStorageSourceAccessRevoke(priv->driver, vm, dd->store);
145     }
146 
147     if (dd->initialized)
148         virStorageSourceDeinit(dd->store);
149 
150     if (dd->blockjob)
151         qemuBlockJobStartupFinalize(vm, dd->blockjob);
152 
153     qemuBlockStorageSourceChainDataFree(dd->crdata);
154     virObjectUnref(dd->terminator);
155     g_free(dd->incrementalBitmap);
156 }
157 
158 
159 static void
qemuBackupDiskDataCleanup(virDomainObj * vm,struct qemuBackupDiskData * dd,size_t ndd)160 qemuBackupDiskDataCleanup(virDomainObj *vm,
161                           struct qemuBackupDiskData *dd,
162                           size_t ndd)
163 {
164     virErrorPtr orig_err;
165     size_t i;
166 
167     if (!dd)
168         return;
169 
170     virErrorPreserveLast(&orig_err);
171 
172     for (i = 0; i < ndd; i++)
173         qemuBackupDiskDataCleanupOne(vm, dd + i);
174 
175     g_free(dd);
176     virErrorRestore(&orig_err);
177 }
178 
179 
180 int
qemuBackupDiskPrepareOneBitmapsChain(virStorageSource * backingChain,virStorageSource * targetsrc,const char * targetbitmap,const char * incremental,virJSONValue * actions,GHashTable * blockNamedNodeData)181 qemuBackupDiskPrepareOneBitmapsChain(virStorageSource *backingChain,
182                                      virStorageSource *targetsrc,
183                                      const char *targetbitmap,
184                                      const char *incremental,
185                                      virJSONValue *actions,
186                                      GHashTable *blockNamedNodeData)
187 {
188     g_autoptr(virJSONValue) tmpactions = NULL;
189 
190     if (qemuBlockGetBitmapMergeActions(backingChain, NULL, targetsrc,
191                                        incremental, targetbitmap, NULL,
192                                        &tmpactions,
193                                        blockNamedNodeData) < 0)
194         return -1;
195 
196     if (tmpactions &&
197         virJSONValueArrayConcat(actions, tmpactions) < 0)
198         return -1;
199 
200     return 0;
201 }
202 
203 
204 static int
qemuBackupDiskPrepareOneBitmaps(struct qemuBackupDiskData * dd,virJSONValue * actions,bool pull,GHashTable * blockNamedNodeData)205 qemuBackupDiskPrepareOneBitmaps(struct qemuBackupDiskData *dd,
206                                 virJSONValue *actions,
207                                 bool pull,
208                                 GHashTable *blockNamedNodeData)
209 {
210     if (!qemuBlockBitmapChainIsValid(dd->domdisk->src,
211                                      dd->backupdisk->incremental,
212                                      blockNamedNodeData)) {
213         virReportError(VIR_ERR_CHECKPOINT_INCONSISTENT,
214                        _("missing or broken bitmap '%s' for disk '%s'"),
215                        dd->backupdisk->incremental, dd->domdisk->dst);
216         return -1;
217     }
218 
219     /* For pull-mode backup, we need the bitmap to be present in the scratch
220      * file as that will be exported. For push-mode backup the bitmap is
221      * actually required on top of the image backing the disk */
222 
223     if (pull) {
224         if (qemuBackupDiskPrepareOneBitmapsChain(dd->domdisk->src,
225                                                  dd->store,
226                                                  dd->incrementalBitmap,
227                                                  dd->backupdisk->incremental,
228                                                  actions,
229                                                  blockNamedNodeData) < 0)
230             return -1;
231     } else {
232         if (qemuBackupDiskPrepareOneBitmapsChain(dd->domdisk->src,
233                                                  dd->domdisk->src,
234                                                  dd->incrementalBitmap,
235                                                  dd->backupdisk->incremental,
236                                                  actions,
237                                                  blockNamedNodeData) < 0)
238             return -1;
239 
240         dd->domdiskIncrementalBitmap = dd->incrementalBitmap;
241     }
242 
243     return 0;
244 }
245 
246 
247 static int
qemuBackupDiskPrepareDataOne(virDomainObj * vm,virDomainBackupDiskDef * backupdisk,struct qemuBackupDiskData * dd,virJSONValue * actions,bool pull,GHashTable * blockNamedNodeData,virQEMUDriverConfig * cfg)248 qemuBackupDiskPrepareDataOne(virDomainObj *vm,
249                              virDomainBackupDiskDef *backupdisk,
250                              struct qemuBackupDiskData *dd,
251                              virJSONValue *actions,
252                              bool pull,
253                              GHashTable *blockNamedNodeData,
254                              virQEMUDriverConfig *cfg)
255 {
256     qemuDomainObjPrivate *priv = vm->privateData;
257 
258     /* set data structure */
259     dd->backupdisk = backupdisk;
260     dd->store = dd->backupdisk->store;
261 
262     if (!(dd->domdisk = virDomainDiskByTarget(vm->def, dd->backupdisk->name))) {
263         virReportError(VIR_ERR_INVALID_ARG,
264                        _("no disk named '%s'"), dd->backupdisk->name);
265         return -1;
266     }
267 
268     if (!qemuDomainDiskBlockJobIsSupported(vm, dd->domdisk))
269         return -1;
270 
271     if (dd->store->format == VIR_STORAGE_FILE_NONE) {
272         dd->store->format = VIR_STORAGE_FILE_QCOW2;
273     } else if (dd->store->format != VIR_STORAGE_FILE_QCOW2) {
274         if (pull) {
275             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
276                            _("pull mode backup for disk '%s' requires qcow2 driver"),
277                            dd->backupdisk->name);
278             return -1;
279         }
280     }
281 
282     /* calculate backing store to use:
283      * push mode:
284      *   full backups: no backing store
285      *   incremental: original disk if format supports backing store
286      * pull mode:
287      *   both: original disk
288      */
289     if (pull || (dd->backupdisk->incremental &&
290                  dd->store->format >= VIR_STORAGE_FILE_BACKING)) {
291         dd->backingStore = dd->domdisk->src;
292     } else {
293         dd->backingStore = dd->terminator = virStorageSourceNew();
294     }
295 
296     if (qemuDomainPrepareStorageSourceBlockdev(NULL, dd->store, priv, cfg) < 0)
297         return -1;
298 
299     if (dd->backupdisk->incremental) {
300         /* We deliberately don't check the config of the disk in the checkpoint
301          * definition as it's not guaranteed that the disks still correspond.
302          * We just verify that a checkpoint exists and later on that the disk
303          * has corresponding bitmap. */
304         if (!virDomainCheckpointFindByName(vm->checkpoints, dd->backupdisk->incremental)) {
305             virReportError(VIR_ERR_NO_DOMAIN_CHECKPOINT,
306                            _("Checkpoint '%s' for incremental backup of disk '%s' not found"),
307                            dd->backupdisk->incremental, dd->backupdisk->name);
308             return -1;
309         }
310 
311         if (dd->backupdisk->exportbitmap)
312             dd->incrementalBitmap = g_strdup(dd->backupdisk->exportbitmap);
313         else
314             dd->incrementalBitmap = g_strdup_printf("backup-%s", dd->domdisk->dst);
315 
316         if (qemuBackupDiskPrepareOneBitmaps(dd, actions, pull, blockNamedNodeData) < 0)
317             return -1;
318     }
319 
320     if (!(dd->blockjob = qemuBlockJobDiskNewBackup(vm, dd->domdisk, dd->store,
321                                                    dd->domdiskIncrementalBitmap)))
322         return -1;
323 
324     /* use original disk as backing to prevent opening the backing chain */
325     if (!(dd->crdata = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(dd->store,
326                                                                            dd->backingStore)))
327         return -1;
328 
329     return 0;
330 }
331 
332 
333 static int
qemuBackupDiskPrepareDataOnePush(virJSONValue * actions,struct qemuBackupDiskData * dd)334 qemuBackupDiskPrepareDataOnePush(virJSONValue *actions,
335                                  struct qemuBackupDiskData *dd)
336 {
337     qemuMonitorTransactionBackupSyncMode syncmode = QEMU_MONITOR_TRANSACTION_BACKUP_SYNC_MODE_FULL;
338 
339     if (dd->incrementalBitmap)
340         syncmode = QEMU_MONITOR_TRANSACTION_BACKUP_SYNC_MODE_INCREMENTAL;
341 
342     if (qemuMonitorTransactionBackup(actions,
343                                      dd->domdisk->src->nodeformat,
344                                      dd->blockjob->name,
345                                      dd->store->nodeformat,
346                                      dd->incrementalBitmap,
347                                      syncmode) < 0)
348         return -1;
349 
350     return 0;
351 }
352 
353 
354 static int
qemuBackupDiskPrepareDataOnePull(virJSONValue * actions,struct qemuBackupDiskData * dd)355 qemuBackupDiskPrepareDataOnePull(virJSONValue *actions,
356                                  struct qemuBackupDiskData *dd)
357 {
358     if (!dd->backupdisk->exportbitmap &&
359         dd->incrementalBitmap)
360         dd->backupdisk->exportbitmap = g_strdup(dd->incrementalBitmap);
361 
362     if (qemuMonitorTransactionBackup(actions,
363                                      dd->domdisk->src->nodeformat,
364                                      dd->blockjob->name,
365                                      dd->store->nodeformat,
366                                      NULL,
367                                      QEMU_MONITOR_TRANSACTION_BACKUP_SYNC_MODE_NONE) < 0)
368         return -1;
369 
370     return 0;
371 }
372 
373 
374 static ssize_t
qemuBackupDiskPrepareData(virDomainObj * vm,virDomainBackupDef * def,GHashTable * blockNamedNodeData,virJSONValue * actions,virQEMUDriverConfig * cfg,struct qemuBackupDiskData ** rdd)375 qemuBackupDiskPrepareData(virDomainObj *vm,
376                           virDomainBackupDef *def,
377                           GHashTable *blockNamedNodeData,
378                           virJSONValue *actions,
379                           virQEMUDriverConfig *cfg,
380                           struct qemuBackupDiskData **rdd)
381 {
382     struct qemuBackupDiskData *disks = NULL;
383     ssize_t ndisks = 0;
384     size_t i;
385     bool pull = def->type == VIR_DOMAIN_BACKUP_TYPE_PULL;
386 
387     disks = g_new0(struct qemuBackupDiskData, def->ndisks);
388 
389     for (i = 0; i < def->ndisks; i++) {
390         virDomainBackupDiskDef *backupdisk = &def->disks[i];
391         struct qemuBackupDiskData *dd = disks + ndisks;
392 
393         if (!backupdisk->store)
394             continue;
395 
396         ndisks++;
397 
398         if (qemuBackupDiskPrepareDataOne(vm, backupdisk, dd, actions, pull,
399                                          blockNamedNodeData, cfg) < 0)
400             goto error;
401 
402         if (pull) {
403             if (qemuBackupDiskPrepareDataOnePull(actions, dd) < 0)
404                 goto error;
405         } else {
406             if (qemuBackupDiskPrepareDataOnePush(actions, dd) < 0)
407                 goto error;
408         }
409     }
410 
411     *rdd = g_steal_pointer(&disks);
412 
413     return ndisks;
414 
415  error:
416     qemuBackupDiskDataCleanup(vm, disks, ndisks);
417     return -1;
418 }
419 
420 
421 static int
qemuBackupDiskPrepareOneStorage(virDomainObj * vm,GHashTable * blockNamedNodeData,struct qemuBackupDiskData * dd,bool reuse_external)422 qemuBackupDiskPrepareOneStorage(virDomainObj *vm,
423                                 GHashTable *blockNamedNodeData,
424                                 struct qemuBackupDiskData *dd,
425                                 bool reuse_external)
426 {
427     qemuDomainObjPrivate *priv = vm->privateData;
428     int rc;
429 
430     if (!reuse_external &&
431         dd->store->type == VIR_STORAGE_TYPE_FILE &&
432         virStorageSourceSupportsCreate(dd->store)) {
433 
434         if (virFileExists(dd->store->path)) {
435             virReportError(VIR_ERR_INVALID_ARG,
436                            _("store '%s' for backup of '%s' exists"),
437                            dd->store->path, dd->domdisk->dst);
438             return -1;
439         }
440 
441         if (qemuDomainStorageFileInit(priv->driver, vm, dd->store, dd->domdisk->src) < 0)
442             return -1;
443 
444         dd->initialized = true;
445 
446         if (virStorageSourceCreate(dd->store) < 0) {
447             virReportSystemError(errno,
448                                  _("failed to create image file '%s'"),
449                                  NULLSTR(dd->store->path));
450             return -1;
451         }
452 
453         dd->created = true;
454     }
455 
456     if (qemuDomainStorageSourceAccessAllow(priv->driver, vm, dd->store,
457                                            false, true, true) < 0)
458         return -1;
459 
460     dd->labelled = true;
461 
462     if (!reuse_external) {
463         if (qemuBlockStorageSourceCreateDetectSize(blockNamedNodeData,
464                                                    dd->store, dd->domdisk->src) < 0)
465             return -1;
466 
467         if (qemuBlockStorageSourceCreate(vm, dd->store, dd->backingStore, NULL,
468                                          dd->crdata->srcdata[0],
469                                          QEMU_ASYNC_JOB_BACKUP) < 0)
470             return -1;
471     } else {
472         if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP) < 0)
473             return -1;
474 
475         rc = qemuBlockStorageSourceAttachApply(priv->mon, dd->crdata->srcdata[0]);
476 
477         if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0)
478             return -1;
479     }
480 
481     dd->added = true;
482 
483     return 0;
484 }
485 
486 
487 static int
qemuBackupDiskPrepareStorage(virDomainObj * vm,struct qemuBackupDiskData * disks,size_t ndisks,GHashTable * blockNamedNodeData,bool reuse_external)488 qemuBackupDiskPrepareStorage(virDomainObj *vm,
489                              struct qemuBackupDiskData *disks,
490                              size_t ndisks,
491                              GHashTable *blockNamedNodeData,
492                              bool reuse_external)
493 {
494     size_t i;
495 
496     for (i = 0; i < ndisks; i++) {
497         if (qemuBackupDiskPrepareOneStorage(vm, blockNamedNodeData, disks + i,
498                                             reuse_external) < 0)
499             return -1;
500     }
501 
502     return 0;
503 }
504 
505 
506 static void
qemuBackupDiskStarted(virDomainObj * vm,struct qemuBackupDiskData * dd,size_t ndd)507 qemuBackupDiskStarted(virDomainObj *vm,
508                       struct qemuBackupDiskData *dd,
509                       size_t ndd)
510 {
511     size_t i;
512 
513     for (i = 0; i < ndd; i++) {
514         dd[i].started = true;
515         dd[i].backupdisk->state = VIR_DOMAIN_BACKUP_DISK_STATE_RUNNING;
516         qemuBlockJobStarted(dd[i].blockjob, vm);
517     }
518 }
519 
520 
521 /**
522  * qemuBackupBeginPullExportDisks:
523  * @vm: domain object
524  * @disks: backup disk data list
525  * @ndisks: number of valid disks in @disks
526  *
527  * Exports all disks from @dd when doing a pull backup in the NBD server. This
528  * function must be called while in the monitor context.
529  */
530 static int
qemuBackupBeginPullExportDisks(virDomainObj * vm,struct qemuBackupDiskData * disks,size_t ndisks)531 qemuBackupBeginPullExportDisks(virDomainObj *vm,
532                                struct qemuBackupDiskData *disks,
533                                size_t ndisks)
534 {
535     size_t i;
536 
537     for (i = 0; i < ndisks; i++) {
538         struct qemuBackupDiskData *dd = disks + i;
539 
540         if (!dd->backupdisk->exportname)
541             dd->backupdisk->exportname = g_strdup(dd->domdisk->dst);
542 
543         if (qemuBlockExportAddNBD(vm, NULL,
544                                   dd->store,
545                                   dd->backupdisk->exportname,
546                                   false,
547                                   dd->incrementalBitmap) < 0)
548             return -1;
549     }
550 
551     return 0;
552 }
553 
554 
555 void
qemuBackupJobTerminate(virDomainObj * vm,qemuDomainJobStatus jobstatus)556 qemuBackupJobTerminate(virDomainObj *vm,
557                        qemuDomainJobStatus jobstatus)
558 
559 {
560     qemuDomainObjPrivate *priv = vm->privateData;
561     g_autoptr(virQEMUDriverConfig) cfg = NULL;
562     size_t i;
563 
564     for (i = 0; i < priv->backup->ndisks; i++) {
565         virDomainBackupDiskDef *backupdisk = priv->backup->disks + i;
566 
567         if (!backupdisk->store)
568             continue;
569 
570         /* restore security label on the images in case the blockjob finishing
571          * handler didn't do so, such as when the VM was destroyed */
572         if (backupdisk->state == VIR_DOMAIN_BACKUP_DISK_STATE_RUNNING ||
573             backupdisk->state == VIR_DOMAIN_BACKUP_DISK_STATE_NONE) {
574             if (qemuSecurityRestoreImageLabel(priv->driver, vm, backupdisk->store,
575                                               false) < 0)
576                 VIR_WARN("Unable to restore security label on %s",
577                          NULLSTR(backupdisk->store->path));
578         }
579 
580         /* delete unneeded images created by libvirt */
581         if (backupdisk->store->type == VIR_STORAGE_TYPE_FILE &&
582             !(priv->backup->apiFlags & VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL) &&
583             (priv->backup->type == VIR_DOMAIN_BACKUP_TYPE_PULL ||
584              (priv->backup->type == VIR_DOMAIN_BACKUP_TYPE_PUSH &&
585               jobstatus != QEMU_DOMAIN_JOB_STATUS_COMPLETED))) {
586 
587             uid_t uid;
588             gid_t gid;
589 
590             if (!cfg)
591                 cfg = virQEMUDriverGetConfig(priv->driver);
592 
593             qemuDomainGetImageIds(cfg, vm, backupdisk->store, NULL, &uid, &gid);
594 
595             if (virFileRemove(backupdisk->store->path, uid, gid) < 0)
596                 VIR_WARN("failed to remove scratch file '%s'",
597                          backupdisk->store->path);
598         }
599     }
600 
601     if (priv->job.current) {
602         qemuDomainJobInfoUpdateTime(priv->job.current);
603 
604         g_clear_pointer(&priv->job.completed, qemuDomainJobInfoFree);
605         priv->job.completed = qemuDomainJobInfoCopy(priv->job.current);
606 
607         priv->job.completed->stats.backup.total = priv->backup->push_total;
608         priv->job.completed->stats.backup.transferred = priv->backup->push_transferred;
609         priv->job.completed->stats.backup.tmp_used = priv->backup->pull_tmp_used;
610         priv->job.completed->stats.backup.tmp_total = priv->backup->pull_tmp_total;
611 
612         priv->job.completed->status = jobstatus;
613         priv->job.completed->errmsg = g_strdup(priv->backup->errmsg);
614 
615         qemuDomainEventEmitJobCompleted(priv->driver, vm);
616     }
617 
618     virDomainBackupDefFree(priv->backup);
619     priv->backup = NULL;
620 
621     if (priv->job.asyncJob == QEMU_ASYNC_JOB_BACKUP)
622         qemuDomainObjEndAsyncJob(priv->driver, vm);
623 }
624 
625 
626 /**
627  * qemuBackupJobCancelBlockjobs:
628  * @vm: domain object
629  * @backup: backup definition
630  * @terminatebackup: flag whether to terminate and unregister the backup
631  * @asyncJob: currently used qemu asynchronous job type
632  *
633  * Sends all active blockjobs which are part of @backup of @vm a signal to
634  * cancel. If @terminatebackup is true qemuBackupJobTerminate is also called
635  * if there are no outstanding active blockjobs.
636  */
637 void
qemuBackupJobCancelBlockjobs(virDomainObj * vm,virDomainBackupDef * backup,bool terminatebackup,int asyncJob)638 qemuBackupJobCancelBlockjobs(virDomainObj *vm,
639                              virDomainBackupDef *backup,
640                              bool terminatebackup,
641                              int asyncJob)
642 {
643     qemuDomainObjPrivate *priv = vm->privateData;
644     size_t i;
645     int rc = 0;
646     bool has_active = false;
647 
648     if (!backup)
649         return;
650 
651     for (i = 0; i < backup->ndisks; i++) {
652         virDomainBackupDiskDef *backupdisk = backup->disks + i;
653         virDomainDiskDef *disk;
654         g_autoptr(qemuBlockJobData) job = NULL;
655 
656         if (!backupdisk->store)
657             continue;
658 
659         /* Look up corresponding disk as backupdisk->idx is no longer reliable */
660         if (!(disk = virDomainDiskByTarget(vm->def, backupdisk->name)))
661             continue;
662 
663         if (!(job = qemuBlockJobDiskGetJob(disk)))
664             continue;
665 
666         if (backupdisk->state != VIR_DOMAIN_BACKUP_DISK_STATE_RUNNING &&
667             backupdisk->state != VIR_DOMAIN_BACKUP_DISK_STATE_CANCELLING)
668             continue;
669 
670         has_active = true;
671 
672         if (backupdisk->state != VIR_DOMAIN_BACKUP_DISK_STATE_RUNNING)
673             continue;
674 
675         if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
676             return;
677 
678         rc = qemuMonitorBlockJobCancel(priv->mon, job->name, true);
679 
680         if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
681             return;
682 
683         if (rc == 0) {
684             backupdisk->state = VIR_DOMAIN_BACKUP_DISK_STATE_CANCELLING;
685             job->state = QEMU_BLOCKJOB_STATE_ABORTING;
686         }
687     }
688 
689     if (terminatebackup && !has_active)
690         qemuBackupJobTerminate(vm, QEMU_DOMAIN_JOB_STATUS_CANCELED);
691 }
692 
693 
694 #define QEMU_BACKUP_TLS_ALIAS_BASE "libvirt_backup"
695 
696 static int
qemuBackupBeginPrepareTLS(virDomainObj * vm,virQEMUDriverConfig * cfg,virDomainBackupDef * def,virJSONValue ** tlsProps,virJSONValue ** tlsSecretProps)697 qemuBackupBeginPrepareTLS(virDomainObj *vm,
698                           virQEMUDriverConfig *cfg,
699                           virDomainBackupDef *def,
700                           virJSONValue **tlsProps,
701                           virJSONValue **tlsSecretProps)
702 {
703     qemuDomainObjPrivate *priv = vm->privateData;
704     g_autofree char *tlsObjAlias = qemuAliasTLSObjFromSrcAlias(QEMU_BACKUP_TLS_ALIAS_BASE);
705     g_autoptr(qemuDomainSecretInfo) secinfo = NULL;
706     const char *tlsKeySecretAlias = NULL;
707 
708     if (def->tls != VIR_TRISTATE_BOOL_YES)
709         return 0;
710 
711     if (!cfg->backupTLSx509certdir) {
712         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
713                        _("backup TLS directory not configured"));
714         return -1;
715     }
716 
717     if (cfg->backupTLSx509secretUUID) {
718         if (!(secinfo = qemuDomainSecretInfoTLSNew(priv, tlsObjAlias,
719                                                    cfg->backupTLSx509secretUUID)))
720             return -1;
721 
722         if (qemuBuildSecretInfoProps(secinfo, tlsSecretProps) < 0)
723             return -1;
724 
725         tlsKeySecretAlias = secinfo->alias;
726     }
727 
728     if (qemuBuildTLSx509BackendProps(cfg->backupTLSx509certdir, true,
729                                      cfg->backupTLSx509verify, tlsObjAlias,
730                                      tlsKeySecretAlias,
731                                      tlsProps) < 0)
732         return -1;
733 
734     return 0;
735 }
736 
737 
738 int
qemuBackupBegin(virDomainObj * vm,const char * backupXML,const char * checkpointXML,unsigned int flags)739 qemuBackupBegin(virDomainObj *vm,
740                 const char *backupXML,
741                 const char *checkpointXML,
742                 unsigned int flags)
743 {
744     qemuDomainObjPrivate *priv = vm->privateData;
745     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver);
746     g_autoptr(virDomainBackupDef) def = NULL;
747     g_autofree char *suffix = NULL;
748     bool pull = false;
749     virDomainMomentObj *chk = NULL;
750     g_autoptr(virDomainCheckpointDef) chkdef = NULL;
751     g_autoptr(virJSONValue) actions = NULL;
752     g_autoptr(virJSONValue) tlsProps = NULL;
753     g_autofree char *tlsAlias = NULL;
754     g_autoptr(virJSONValue) tlsSecretProps = NULL;
755     g_autofree char *tlsSecretAlias = NULL;
756     struct qemuBackupDiskData *dd = NULL;
757     ssize_t ndd = 0;
758     g_autoptr(GHashTable) blockNamedNodeData = NULL;
759     bool job_started = false;
760     bool nbd_running = false;
761     bool reuse = (flags & VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL);
762     int rc = 0;
763     int ret = -1;
764 
765     virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL, -1);
766 
767     if (!(def = virDomainBackupDefParseString(backupXML, priv->driver->xmlopt, 0)))
768         return -1;
769 
770     if (checkpointXML) {
771         if (!(chkdef = virDomainCheckpointDefParseString(checkpointXML,
772                                                          priv->driver->xmlopt,
773                                                          priv->qemuCaps, 0)))
774             return -1;
775 
776         suffix = g_strdup(chkdef->parent.name);
777     } else {
778         gint64 now_us = g_get_real_time();
779         suffix = g_strdup_printf("%lld", (long long)now_us/(1000*1000));
780     }
781 
782     if (def->type == VIR_DOMAIN_BACKUP_TYPE_PULL)
783         pull = true;
784 
785     def->apiFlags = flags;
786 
787     /* we'll treat this kind of backup job as an asyncjob as it uses some of the
788      * infrastructure for async jobs. We'll allow standard modify-type jobs
789      * as the interlocking of conflicting operations is handled on the block
790      * job level */
791     if (qemuDomainObjBeginAsyncJob(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP,
792                                    VIR_DOMAIN_JOB_OPERATION_BACKUP, flags) < 0)
793         return -1;
794 
795     qemuDomainObjSetAsyncJobMask(vm, (QEMU_JOB_DEFAULT_MASK |
796                                       JOB_MASK(QEMU_JOB_SUSPEND) |
797                                       JOB_MASK(QEMU_JOB_MODIFY)));
798     priv->job.current->statsType = QEMU_DOMAIN_JOB_STATS_TYPE_BACKUP;
799 
800     if (!virDomainObjIsActive(vm)) {
801         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
802                        _("cannot perform disk backup for inactive domain"));
803         goto endjob;
804     }
805 
806     if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_BACKUP)) {
807         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
808                        _("backup is not supported with this QEMU"));
809         goto endjob;
810     }
811 
812     if (virDomainBackupAlignDisks(def, vm->def, suffix) < 0)
813         goto endjob;
814 
815     if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP)) {
816         size_t i;
817 
818         if (chkdef) {
819             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
820                            _("creating checkpoint for incremental backup is not supported yet"));
821             goto endjob;
822         }
823 
824         for (i = 0; i < def->ndisks; i++) {
825             if (def->disks[i].backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL) {
826                 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
827                                _("incremental backup is not supported yet"));
828                 goto endjob;
829             }
830         }
831     }
832 
833     if (priv->backup) {
834         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
835                        _("another backup job is already running"));
836         goto endjob;
837     }
838 
839     if (qemuBackupPrepare(def) < 0)
840         goto endjob;
841 
842     if (qemuBackupBeginPrepareTLS(vm, cfg, def, &tlsProps, &tlsSecretProps) < 0)
843         goto endjob;
844 
845     actions = virJSONValueNewArray();
846 
847     /* The 'chk' checkpoint must be rolled back if the transaction command
848      * which creates it on disk is not executed or fails */
849     if (chkdef) {
850         if (qemuCheckpointCreateCommon(priv->driver, vm, &chkdef,
851                                        &actions, &chk) < 0)
852             goto endjob;
853     }
854 
855     if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_BACKUP)))
856         goto endjob;
857 
858     if ((ndd = qemuBackupDiskPrepareData(vm, def, blockNamedNodeData, actions,
859                                          cfg, &dd)) <= 0) {
860         if (ndd == 0) {
861             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
862                            _("no disks selected for backup"));
863         }
864 
865         goto endjob;
866     }
867 
868     if (qemuBackupDiskPrepareStorage(vm, dd, ndd, blockNamedNodeData, reuse) < 0)
869         goto endjob;
870 
871     priv->backup = g_steal_pointer(&def);
872 
873     if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP) < 0)
874         goto endjob;
875 
876     if (pull) {
877         if (tlsSecretProps)
878             rc = qemuMonitorAddObject(priv->mon, &tlsSecretProps, &tlsSecretAlias);
879 
880         if (rc == 0 && tlsProps)
881             rc = qemuMonitorAddObject(priv->mon, &tlsProps, &tlsAlias);
882 
883         if (rc == 0) {
884             if ((rc = qemuMonitorNBDServerStart(priv->mon, priv->backup->server, tlsAlias)) == 0)
885                 nbd_running = true;
886         }
887     }
888 
889     if (rc == 0)
890         rc = qemuMonitorTransaction(priv->mon, &actions);
891 
892     if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0)
893         goto endjob;
894 
895     job_started = true;
896     priv->backup->tlsAlias = g_steal_pointer(&tlsAlias);
897     priv->backup->tlsSecretAlias = g_steal_pointer(&tlsSecretAlias);
898     /* qemuBackupDiskStarted saves the status XML */
899     qemuBackupDiskStarted(vm, dd, ndd);
900 
901     if (chk) {
902         virDomainMomentObj *tmpchk = g_steal_pointer(&chk);
903         if (qemuCheckpointCreateFinalize(priv->driver, vm, cfg, tmpchk, true) < 0)
904             goto endjob;
905     }
906 
907     if (pull) {
908         if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP) < 0)
909             goto endjob;
910         /* note that if the export fails we've already created the checkpoint
911          * and we will not delete it */
912         rc = qemuBackupBeginPullExportDisks(vm, dd, ndd);
913         if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
914             goto endjob;
915 
916         if (rc < 0) {
917             qemuBackupJobCancelBlockjobs(vm, priv->backup, false, QEMU_ASYNC_JOB_BACKUP);
918             goto endjob;
919         }
920     }
921 
922     ret = 0;
923 
924  endjob:
925     qemuBackupDiskDataCleanup(vm, dd, ndd);
926 
927     /* if 'chk' is non-NULL here it's a failure and it must be rolled back */
928     qemuCheckpointRollbackMetadata(vm, chk);
929 
930     if (!job_started && (nbd_running || tlsAlias || tlsSecretAlias) &&
931         qemuDomainObjEnterMonitorAsync(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP) == 0) {
932         if (nbd_running)
933             ignore_value(qemuMonitorNBDServerStop(priv->mon));
934         if (tlsAlias)
935             ignore_value(qemuMonitorDelObject(priv->mon, tlsAlias, false));
936         if (tlsSecretAlias)
937             ignore_value(qemuMonitorDelObject(priv->mon, tlsSecretAlias, false));
938         ignore_value(qemuDomainObjExitMonitor(priv->driver, vm));
939     }
940 
941     if (ret < 0 && !job_started && priv->backup)
942         def = g_steal_pointer(&priv->backup);
943 
944     if (ret == 0)
945         qemuDomainObjReleaseAsyncJob(vm);
946     else
947         qemuDomainObjEndAsyncJob(priv->driver, vm);
948 
949     return ret;
950 }
951 
952 
953 char *
qemuBackupGetXMLDesc(virDomainObj * vm,unsigned int flags)954 qemuBackupGetXMLDesc(virDomainObj *vm,
955                      unsigned int flags)
956 {
957     qemuDomainObjPrivate *priv = vm->privateData;
958 
959     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
960     virDomainBackupDef *backup;
961 
962     virCheckFlags(0, NULL);
963 
964     if (!(backup = qemuDomainGetBackup(vm)))
965         return NULL;
966 
967     if (virDomainBackupDefFormat(&buf, backup, false, priv->driver->xmlopt) < 0)
968         return NULL;
969 
970     return virBufferContentAndReset(&buf);
971 }
972 
973 
974 void
qemuBackupNotifyBlockjobEnd(virDomainObj * vm,virDomainDiskDef * disk,qemuBlockjobState state,const char * errmsg,unsigned long long cur,unsigned long long end,int asyncJob)975 qemuBackupNotifyBlockjobEnd(virDomainObj *vm,
976                             virDomainDiskDef *disk,
977                             qemuBlockjobState state,
978                             const char *errmsg,
979                             unsigned long long cur,
980                             unsigned long long end,
981                             int asyncJob)
982 {
983     qemuDomainObjPrivate *priv = vm->privateData;
984     bool has_running = false;
985     bool has_cancelling = false;
986     bool has_cancelled = false;
987     bool has_failed = false;
988     qemuDomainJobStatus jobstatus = QEMU_DOMAIN_JOB_STATUS_COMPLETED;
989     virDomainBackupDef *backup = priv->backup;
990     size_t i;
991 
992     VIR_DEBUG("vm: '%s', disk:'%s', state:'%d' errmsg:'%s'",
993               vm->def->name, disk->dst, state, NULLSTR(errmsg));
994 
995     if (!backup)
996         return;
997 
998     if (backup->type == VIR_DOMAIN_BACKUP_TYPE_PULL) {
999         if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
1000             return;
1001         ignore_value(qemuMonitorNBDServerStop(priv->mon));
1002         if (backup->tlsAlias)
1003             ignore_value(qemuMonitorDelObject(priv->mon, backup->tlsAlias, false));
1004         if (backup->tlsSecretAlias)
1005             ignore_value(qemuMonitorDelObject(priv->mon, backup->tlsSecretAlias, false));
1006         if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
1007             return;
1008 
1009         /* update the final statistics with the current job's data */
1010         backup->pull_tmp_used += cur;
1011         backup->pull_tmp_total += end;
1012     } else {
1013         backup->push_transferred += cur;
1014         backup->push_total += end;
1015     }
1016 
1017     /* record first error message */
1018     if (!backup->errmsg)
1019         backup->errmsg = g_strdup(errmsg);
1020 
1021     for (i = 0; i < backup->ndisks; i++) {
1022         virDomainBackupDiskDef *backupdisk = backup->disks + i;
1023 
1024         if (!backupdisk->store)
1025             continue;
1026 
1027         if (STREQ(disk->dst, backupdisk->name)) {
1028             switch (state) {
1029             case QEMU_BLOCKJOB_STATE_COMPLETED:
1030                 backupdisk->state = VIR_DOMAIN_BACKUP_DISK_STATE_COMPLETE;
1031                 break;
1032 
1033             case QEMU_BLOCKJOB_STATE_CONCLUDED:
1034             case QEMU_BLOCKJOB_STATE_FAILED:
1035                 backupdisk->state = VIR_DOMAIN_BACKUP_DISK_STATE_FAILED;
1036                 break;
1037 
1038             case QEMU_BLOCKJOB_STATE_CANCELLED:
1039                 backupdisk->state = VIR_DOMAIN_BACKUP_DISK_STATE_CANCELLED;
1040                 break;
1041 
1042             case QEMU_BLOCKJOB_STATE_READY:
1043             case QEMU_BLOCKJOB_STATE_NEW:
1044             case QEMU_BLOCKJOB_STATE_RUNNING:
1045             case QEMU_BLOCKJOB_STATE_ABORTING:
1046             case QEMU_BLOCKJOB_STATE_PIVOTING:
1047             case QEMU_BLOCKJOB_STATE_LAST:
1048             default:
1049                 break;
1050             }
1051         }
1052 
1053         switch (backupdisk->state) {
1054         case VIR_DOMAIN_BACKUP_DISK_STATE_COMPLETE:
1055             break;
1056 
1057         case VIR_DOMAIN_BACKUP_DISK_STATE_RUNNING:
1058             has_running = true;
1059             break;
1060 
1061         case VIR_DOMAIN_BACKUP_DISK_STATE_CANCELLING:
1062             has_cancelling = true;
1063             break;
1064 
1065         case VIR_DOMAIN_BACKUP_DISK_STATE_FAILED:
1066             has_failed = true;
1067             break;
1068 
1069         case VIR_DOMAIN_BACKUP_DISK_STATE_CANCELLED:
1070             has_cancelled = true;
1071             break;
1072 
1073         case VIR_DOMAIN_BACKUP_DISK_STATE_NONE:
1074         case VIR_DOMAIN_BACKUP_DISK_STATE_LAST:
1075             break;
1076         }
1077     }
1078 
1079     if (has_running && (has_failed || has_cancelled)) {
1080         /* cancel the rest of the jobs */
1081         qemuBackupJobCancelBlockjobs(vm, backup, false, asyncJob);
1082     } else if (!has_running && !has_cancelling) {
1083         /* all sub-jobs have stopped */
1084 
1085         if (has_failed)
1086             jobstatus = QEMU_DOMAIN_JOB_STATUS_FAILED;
1087         else if (has_cancelled && backup->type == VIR_DOMAIN_BACKUP_TYPE_PUSH)
1088             jobstatus = QEMU_DOMAIN_JOB_STATUS_CANCELED;
1089 
1090         qemuBackupJobTerminate(vm, jobstatus);
1091     }
1092 
1093     /* otherwise we must wait for the jobs to end */
1094 }
1095 
1096 
1097 static void
qemuBackupGetJobInfoStatsUpdateOne(virDomainObj * vm,bool push,const char * diskdst,qemuDomainBackupStats * stats,qemuMonitorJobInfo ** blockjobs,size_t nblockjobs)1098 qemuBackupGetJobInfoStatsUpdateOne(virDomainObj *vm,
1099                                    bool push,
1100                                    const char *diskdst,
1101                                    qemuDomainBackupStats *stats,
1102                                    qemuMonitorJobInfo **blockjobs,
1103                                    size_t nblockjobs)
1104 {
1105     virDomainDiskDef *domdisk;
1106     qemuMonitorJobInfo *monblockjob = NULL;
1107     g_autoptr(qemuBlockJobData) diskblockjob = NULL;
1108     size_t i;
1109 
1110     /* it's just statistics so let's not worry so much about errors */
1111     if (!(domdisk = virDomainDiskByTarget(vm->def, diskdst)))
1112         return;
1113 
1114     if (!(diskblockjob = qemuBlockJobDiskGetJob(domdisk)))
1115         return;
1116 
1117     for (i = 0; i < nblockjobs; i++) {
1118         if (STREQ_NULLABLE(blockjobs[i]->id, diskblockjob->name)) {
1119             monblockjob = blockjobs[i];
1120             break;
1121         }
1122     }
1123     if (!monblockjob)
1124         return;
1125 
1126     if (push) {
1127         stats->total += monblockjob->progressTotal;
1128         stats->transferred += monblockjob->progressCurrent;
1129     } else {
1130         stats->tmp_used += monblockjob->progressCurrent;
1131         stats->tmp_total += monblockjob->progressTotal;
1132     }
1133 }
1134 
1135 
1136 int
qemuBackupGetJobInfoStats(virQEMUDriver * driver,virDomainObj * vm,qemuDomainJobInfo * jobInfo)1137 qemuBackupGetJobInfoStats(virQEMUDriver *driver,
1138                           virDomainObj *vm,
1139                           qemuDomainJobInfo *jobInfo)
1140 {
1141     qemuDomainBackupStats *stats = &jobInfo->stats.backup;
1142     qemuDomainObjPrivate *priv = vm->privateData;
1143     qemuMonitorJobInfo **blockjobs = NULL;
1144     size_t nblockjobs = 0;
1145     size_t i;
1146     int rc;
1147     int ret = -1;
1148 
1149     if (!priv->backup) {
1150         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1151                        _("backup job data missing"));
1152         return -1;
1153     }
1154 
1155     if (qemuDomainJobInfoUpdateTime(jobInfo) < 0)
1156         return -1;
1157 
1158     jobInfo->status = QEMU_DOMAIN_JOB_STATUS_ACTIVE;
1159 
1160     qemuDomainObjEnterMonitor(driver, vm);
1161 
1162     rc = qemuMonitorGetJobInfo(priv->mon, &blockjobs, &nblockjobs);
1163 
1164     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
1165         goto cleanup;
1166 
1167     /* count in completed jobs */
1168     stats->total = priv->backup->push_total;
1169     stats->transferred = priv->backup->push_transferred;
1170     stats->tmp_used = priv->backup->pull_tmp_used;
1171     stats->tmp_total = priv->backup->pull_tmp_total;
1172 
1173     for (i = 0; i < priv->backup->ndisks; i++) {
1174         if (priv->backup->disks[i].state != VIR_DOMAIN_BACKUP_DISK_STATE_RUNNING)
1175             continue;
1176 
1177         qemuBackupGetJobInfoStatsUpdateOne(vm,
1178                                            priv->backup->type == VIR_DOMAIN_BACKUP_TYPE_PUSH,
1179                                            priv->backup->disks[i].name,
1180                                            stats,
1181                                            blockjobs,
1182                                            nblockjobs);
1183     }
1184 
1185     ret = 0;
1186 
1187  cleanup:
1188     for (i = 0; i < nblockjobs; i++)
1189         qemuMonitorJobInfoFree(blockjobs[i]);
1190     g_free(blockjobs);
1191     return ret;
1192 }
1193