From 7e5b993d3b8cae9c43b753591a7b12db5c540da5 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Thu, 25 Jun 2020 16:16:14 +0200 Subject: [PATCH] backup: Allow configuring incremental backup per-disk individually The semantics of the backup operation don't strictly require that all disks being backed up are part of the same incremental part (when a disk was checkpointed/backed up separately or in a different VM), or even they may not have a previous checkpoint at all (e.g. when the disk was freshly hotplugged to the vm). In such cases we can still create a common checkpoint for all of them and backup differences according to configuration. This patch adds a per-disk configuration of the checkpoint to do the incremental backup from via the 'incremental' attribute and allows perform full backups via the 'backupmode' attribute. Note that no changes to the qemu driver are necessary to take advantage of this as we already obey the per-disk 'incremental' field. https://bugzilla.redhat.com/show_bug.cgi?id=1829829 Signed-off-by: Peter Krempa Reviewed-by: Eric Blake --- docs/formatbackup.rst | 11 +++++ docs/schemas/domainbackup.rng | 23 +++++++++ src/conf/backup_conf.c | 49 ++++++++++++++++++- src/conf/backup_conf.h | 11 +++++ tests/domainbackupxml2xmlin/backup-pull.xml | 12 +++++ .../backup-pull-encrypted.xml | 6 +-- .../backup-pull-internal-invalid.xml | 6 +-- .../backup-pull-seclabel.xml | 4 +- tests/domainbackupxml2xmlout/backup-pull.xml | 14 +++++- .../backup-push-encrypted.xml | 6 +-- .../backup-push-seclabel.xml | 4 +- tests/domainbackupxml2xmlout/backup-push.xml | 2 +- tests/domainbackupxml2xmlout/empty.xml | 2 +- 13 files changed, 133 insertions(+), 17 deletions(-) diff --git a/docs/formatbackup.rst b/docs/formatbackup.rst index 17431fe51a..1b9e6ebb22 100644 --- a/docs/formatbackup.rst +++ b/docs/formatbackup.rst @@ -69,6 +69,17 @@ were supplied). The following child elements and attributes are supported: should take part in the backup and using ``no`` excludes the disk from the backup. + ``backupmode`` + This attribute overrides the implied backup mode inherited from the + definition of the backup itself. Value ``full`` forces a full backup + even if the backup calls for an incremental backup, and ``incremental`` + coupled with the attribute ``incremental='CHECKPOINTNAME`` for the disk + forces an incremental backup from ``CHECKPOINTNAME``. + + ``incremental`` + An optional attribute giving the name of an existing checkpoint of the + domain which overrides the one set by the ```` element. + ``exportname`` Allows modification of the NBD export name for the given disk. By default equal to disk target. Valid only for pull mode backups. diff --git a/docs/schemas/domainbackup.rng b/docs/schemas/domainbackup.rng index c0e17f512b..579b62a658 100644 --- a/docs/schemas/domainbackup.rng +++ b/docs/schemas/domainbackup.rng @@ -96,6 +96,27 @@ + + + + + + full + + + + + incremental + + + + + + + + + + @@ -134,6 +155,7 @@ + @@ -203,6 +225,7 @@ + diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index 5e4144d371..02319f7245 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -56,6 +56,13 @@ VIR_ENUM_IMPL(virDomainBackupDiskState, "cancelling", "cancelled"); +VIR_ENUM_DECL(virDomainBackupDiskBackupMode); +VIR_ENUM_IMPL(virDomainBackupDiskBackupMode, + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_LAST, + "", + "full", + "incremental"); + void virDomainBackupDefFree(virDomainBackupDefPtr def) { @@ -100,6 +107,7 @@ virDomainBackupDiskDefParseXML(xmlNodePtr node, g_autofree char *driver = NULL; g_autofree char *backup = NULL; g_autofree char *state = NULL; + g_autofree char *backupmode = NULL; int tmp; xmlNodePtr srcNode; unsigned int storageSourceParseFlags = 0; @@ -137,6 +145,19 @@ virDomainBackupDiskDefParseXML(xmlNodePtr node, def->exportbitmap = virXMLPropString(node, "exportbitmap"); } + if ((backupmode = virXMLPropString(node, "backupmode"))) { + if ((tmp = virDomainBackupDiskBackupModeTypeFromString(backupmode)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid backupmode '%s' of disk '%s'"), + backupmode, def->name); + return -1; + } + + def->backupmode = tmp; + } + + def->incremental = virXMLPropString(node, "incremental"); + if (internal) { if (!(state = virXMLPropString(node, "state")) || (tmp = virDomainBackupDiskStateTypeFromString(state)) < 0) { @@ -376,6 +397,13 @@ virDomainBackupDiskDefFormat(virBufferPtr buf, if (disk->backup == VIR_TRISTATE_BOOL_YES) { virBufferAsprintf(&attrBuf, " type='%s'", virStorageTypeToString(disk->store->type)); + if (disk->backupmode != VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_DEFAULT) { + virBufferAsprintf(&attrBuf, " backupmode='%s'", + virDomainBackupDiskBackupModeTypeToString(disk->backupmode)); + } + + virBufferEscapeString(&attrBuf, " incremental='%s'", disk->incremental); + virBufferEscapeString(&attrBuf, " exportname='%s'", disk->exportname); virBufferEscapeString(&attrBuf, " exportbitmap='%s'", disk->exportbitmap); @@ -524,6 +552,16 @@ virDomainBackupAlignDisks(virDomainBackupDefPtr def, return -1; } + if (backupdisk->backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL && + !backupdisk->incremental && + !def->incremental) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("'incremental' backup mode of disk '%s' requires setting 'incremental' field for disk or backup"), + backupdisk->name); + return -1; + } + + if (backupdisk->backup == VIR_TRISTATE_BOOL_YES && virDomainBackupDefAssignStore(backupdisk, domdisk->src, suffix) < 0) return -1; @@ -561,7 +599,16 @@ virDomainBackupAlignDisks(virDomainBackupDefPtr def, for (i = 0; i < def->ndisks; i++) { virDomainBackupDiskDefPtr backupdisk = &def->disks[i]; - if (def->incremental && !backupdisk->incremental) + if (backupdisk->backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_DEFAULT) { + if (def->incremental || backupdisk->incremental) { + backupdisk->backupmode = VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL; + } else { + backupdisk->backupmode = VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_FULL; + } + } + + if (!backupdisk->incremental && + backupdisk->backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL) backupdisk->incremental = g_strdup(def->incremental); } diff --git a/src/conf/backup_conf.h b/src/conf/backup_conf.h index aa2d6d4b68..bda2bdcfe4 100644 --- a/src/conf/backup_conf.h +++ b/src/conf/backup_conf.h @@ -45,12 +45,23 @@ typedef enum { VIR_DOMAIN_BACKUP_DISK_STATE_LAST } virDomainBackupDiskState; + +typedef enum { + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_DEFAULT = 0, + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_FULL, + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL, + + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_LAST +} virDomainBackupDiskBackupMode; + + /* Stores disk-backup information */ typedef struct _virDomainBackupDiskDef virDomainBackupDiskDef; typedef virDomainBackupDiskDef *virDomainBackupDiskDefPtr; struct _virDomainBackupDiskDef { char *name; /* name matching the + + + + + + + + + + + + diff --git a/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml b/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml index 3c3042111d..42051d1d24 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml @@ -2,7 +2,7 @@ 1525889631 - + @@ -10,7 +10,7 @@ - + @@ -18,7 +18,7 @@ - + diff --git a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml index 9702978ce0..092b6bf8a7 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml @@ -2,7 +2,7 @@ 1525889631 - + @@ -10,7 +10,7 @@ - + @@ -18,7 +18,7 @@ - + diff --git a/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml b/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml index 38330394f7..385d949ae3 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml @@ -2,13 +2,13 @@ 1525889631 - + - + diff --git a/tests/domainbackupxml2xmlout/backup-pull.xml b/tests/domainbackupxml2xmlout/backup-pull.xml index 4952270a5a..1762ba72b5 100644 --- a/tests/domainbackupxml2xmlout/backup-pull.xml +++ b/tests/domainbackupxml2xmlout/backup-pull.xml @@ -2,10 +2,22 @@ 1525889631 - + + + + + + + + + + + + + diff --git a/tests/domainbackupxml2xmlout/backup-push-encrypted.xml b/tests/domainbackupxml2xmlout/backup-push-encrypted.xml index 2a5aad93cd..3b664b0dcb 100644 --- a/tests/domainbackupxml2xmlout/backup-push-encrypted.xml +++ b/tests/domainbackupxml2xmlout/backup-push-encrypted.xml @@ -1,7 +1,7 @@ 1525889631 - + @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ - + diff --git a/tests/domainbackupxml2xmlout/backup-push-seclabel.xml b/tests/domainbackupxml2xmlout/backup-push-seclabel.xml index 59af3e6a6c..9a0d2b3061 100644 --- a/tests/domainbackupxml2xmlout/backup-push-seclabel.xml +++ b/tests/domainbackupxml2xmlout/backup-push-seclabel.xml @@ -1,13 +1,13 @@ 1525889631 - + - + diff --git a/tests/domainbackupxml2xmlout/backup-push.xml b/tests/domainbackupxml2xmlout/backup-push.xml index bc11a93d94..317dcf6e47 100644 --- a/tests/domainbackupxml2xmlout/backup-push.xml +++ b/tests/domainbackupxml2xmlout/backup-push.xml @@ -1,7 +1,7 @@ 1525889631 - + diff --git a/tests/domainbackupxml2xmlout/empty.xml b/tests/domainbackupxml2xmlout/empty.xml index 52d2b4f0af..b1cbd154ab 100644 --- a/tests/domainbackupxml2xmlout/empty.xml +++ b/tests/domainbackupxml2xmlout/empty.xml @@ -1,6 +1,6 @@ - +