]> xenbits.xensource.com Git - libvirt.git/commitdiff
backup: Allow configuring incremental backup per-disk individually
authorPeter Krempa <pkrempa@redhat.com>
Thu, 25 Jun 2020 14:16:14 +0000 (16:16 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Wed, 8 Jul 2020 06:40:30 +0000 (08:40 +0200)
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 <pkrempa@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
13 files changed:
docs/formatbackup.rst
docs/schemas/domainbackup.rng
src/conf/backup_conf.c
src/conf/backup_conf.h
tests/domainbackupxml2xmlin/backup-pull.xml
tests/domainbackupxml2xmlout/backup-pull-encrypted.xml
tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml
tests/domainbackupxml2xmlout/backup-pull-seclabel.xml
tests/domainbackupxml2xmlout/backup-pull.xml
tests/domainbackupxml2xmlout/backup-push-encrypted.xml
tests/domainbackupxml2xmlout/backup-push-seclabel.xml
tests/domainbackupxml2xmlout/backup-push.xml
tests/domainbackupxml2xmlout/empty.xml

index 17431fe51ad4ec1bbabd1875e7c889796e09ecd9..1b9e6ebb226026456d0c7943ac8ad2da27f6c0c1 100644 (file)
@@ -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 ``<incremental>`` 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.
index c0e17f512bd11d2a6f35bcd97cd2faca29d6ef84..579b62a658a9380ad62cb3bfb2a2db7507636f5e 100644 (file)
     </element>
   </define>
 
+
+  <define name='backupDiskMode'>
+    <optional>
+      <choice>
+        <attribute name='backupmode'>
+          <value>full</value>
+        </attribute>
+        <group>
+          <optional>
+            <attribute name='backupmode'>
+              <value>incremental</value>
+            </attribute>
+          </optional>
+          <optional>
+            <attribute name='incremental'/>
+          </optional>
+        </group>
+      </choice>
+    </optional>
+  </define>
+
   <define name='backupPushDriver'>
     <optional>
       <element name='driver'>
             <attribute name='name'>
               <ref name='diskTarget'/>
             </attribute>
+            <ref name='backupDiskMode'/>
             <choice>
               <group>
                 <attribute name='backup'>
             <attribute name='name'>
               <ref name='diskTarget'/>
             </attribute>
+            <ref name='backupDiskMode'/>
             <optional>
               <attribute name='exportname'>
                 <text/>
index 5e4144d37103d9e4bbc83f02c895e46a6d913910..02319f72452243662350e65d3765809a4a3c162e 100644 (file)
@@ -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);
     }
 
index aa2d6d4b681a99c0c5432059ae06739b4e4aed10..bda2bdcfe4d823b78c7c201965c2b98d5ef323ab 100644 (file)
@@ -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 <target dev='...' of the domain */
     virTristateBool backup; /* whether backup is requested */
+    virDomainBackupDiskBackupMode backupmode;
     char *incremental; /* name of the starting point checkpoint of an incremental backup */
     char *exportname; /* name of the NBD export for pull mode backup */
     char *exportbitmap; /* name of the bitmap exposed in NBD for pull mode backup */
index c0bea4771d9d1880128644e62fecb0f2fa3b91dd..c51f0995ac6d6631f32d0f2dfde65280b35f5fd3 100644 (file)
@@ -6,5 +6,17 @@
       <scratch file='/path/to/file'/>
     </disk>
     <disk name='hda' backup='no'/>
+    <disk name='vdc' type='file' backupmode='full'>
+      <scratch file='/path/to/file'/>
+    </disk>
+    <disk name='vdd' type='file' backupmode='incremental'>
+      <scratch file='/path/to/file'/>
+    </disk>
+    <disk name='vde' type='file' backupmode='incremental' incremental='blah'>
+      <scratch file='/path/to/file'/>
+    </disk>
+    <disk name='vdf' type='file' incremental='bleh'>
+      <scratch file='/path/to/file'/>
+    </disk>
   </disks>
 </domainbackup>
index 3c3042111df689fd5119fff14f1d18ae11ba1c83..42051d1d24be03f92d955119b5f4a60ebe1dd676 100644 (file)
@@ -2,7 +2,7 @@
   <incremental>1525889631</incremental>
   <server transport='tcp' tls='yes' name='localhost' port='10809'/>
   <disks>
-    <disk name='vda' backup='yes' type='file' exportname='test-vda' exportbitmap='blah'>
+    <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'>
       <driver type='qcow2'/>
       <scratch file='/path/to/file'>
         <encryption format='luks'>
@@ -10,7 +10,7 @@
         </encryption>
       </scratch>
     </disk>
-    <disk name='vdb' backup='yes' type='file' exportname='test-vda' exportbitmap='blah'>
+    <disk name='vdb' backup='yes' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'>
       <driver type='qcow2'/>
       <scratch file='/path/to/file'>
         <encryption format='luks'>
@@ -18,7 +18,7 @@
         </encryption>
       </scratch>
     </disk>
-    <disk name='vdc' backup='yes' type='block'>
+    <disk name='vdc' backup='yes' type='block' backupmode='incremental' incremental='1525889631'>
       <driver type='qcow2'/>
       <scratch dev='/dev/block'>
         <encryption format='luks'>
index 9702978ce0b7d8b30a86f1b6c90e324d01d66bfe..092b6bf8a79272c9240dab981de0ca57e278fd86 100644 (file)
@@ -2,7 +2,7 @@
   <incremental>1525889631</incremental>
   <server transport='tcp' tls='yes' name='localhost' port='10809'/>
   <disks>
-    <disk name='vda' backup='yes' state='running' type='file' exportname='test-vda' exportbitmap='blah'>
+    <disk name='vda' backup='yes' state='running' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'>
       <driver type='qcow2'/>
       <scratch file='/path/to/file'>
         <encryption format='luks'>
@@ -10,7 +10,7 @@
         </encryption>
       </scratch>
     </disk>
-    <disk name='vdb' backup='yes' state='complete' type='file' exportname='test-vda' exportbitmap='blah'>
+    <disk name='vdb' backup='yes' state='complete' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'>
       <driver type='qcow2'/>
       <scratch file='/path/to/file'>
         <encryption format='luks'>
@@ -18,7 +18,7 @@
         </encryption>
       </scratch>
     </disk>
-    <disk name='vdc' backup='yes' state='running' type='block'>
+    <disk name='vdc' backup='yes' state='running' type='block' backupmode='incremental' incremental='1525889631'>
       <driver type='qcow2'/>
       <scratch dev='/dev/block'>
         <encryption format='luks'>
index 38330394f7cd5a65d9308d4d3a9e248f3037b299..385d949ae35cd8548a27aa1b63d67b4365141629 100644 (file)
@@ -2,13 +2,13 @@
   <incremental>1525889631</incremental>
   <server transport='tcp' name='localhost' port='10809'/>
   <disks>
-    <disk name='vda' backup='yes' type='file' exportname='test-vda' exportbitmap='blah'>
+    <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'>
       <driver type='qcow2'/>
       <scratch file='/path/to/file'>
         <seclabel model='dac' relabel='no'/>
       </scratch>
     </disk>
-    <disk name='vdb' backup='yes' type='block'>
+    <disk name='vdb' backup='yes' type='block' backupmode='incremental' incremental='1525889631'>
       <driver type='qcow2'/>
       <scratch dev='/dev/block'>
         <seclabel model='dac' relabel='no'/>
index 4952270a5aff946c76ad80e3726be21fbdb34a2d..1762ba72b5cdbce5ac847e799c09440a492c1a02 100644 (file)
@@ -2,10 +2,22 @@
   <incremental>1525889631</incremental>
   <server transport='tcp' name='localhost' port='10809'/>
   <disks>
-    <disk name='vda' backup='yes' type='file'>
+    <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'>
       <scratch file='/path/to/file'/>
     </disk>
     <disk name='hda' backup='no'/>
+    <disk name='vdc' backup='yes' type='file' backupmode='full'>
+      <scratch file='/path/to/file'/>
+    </disk>
+    <disk name='vdd' backup='yes' type='file' backupmode='incremental' incremental='1525889631'>
+      <scratch file='/path/to/file'/>
+    </disk>
+    <disk name='vde' backup='yes' type='file' backupmode='incremental' incremental='blah'>
+      <scratch file='/path/to/file'/>
+    </disk>
+    <disk name='vdf' backup='yes' type='file' backupmode='incremental' incremental='bleh'>
+      <scratch file='/path/to/file'/>
+    </disk>
     <disk name='vdextradisk' backup='no'/>
   </disks>
 </domainbackup>
index 2a5aad93cd5c780cf6bfa9a1712e13d43d97f449..3b664b0dcbe9ec60428f18c43ab5e3047e60e538 100644 (file)
@@ -1,7 +1,7 @@
 <domainbackup mode='push'>
   <incremental>1525889631</incremental>
   <disks>
-    <disk name='vda' backup='yes' type='file'>
+    <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'>
       <driver type='qcow2'/>
       <target file='/path/to/file'>
         <encryption format='luks'>
@@ -9,7 +9,7 @@
         </encryption>
       </target>
     </disk>
-    <disk name='vdb' backup='yes' type='file'>
+    <disk name='vdb' backup='yes' type='file' backupmode='incremental' incremental='1525889631'>
       <driver type='raw'/>
       <target file='/path/to/file'>
         <encryption format='luks'>
@@ -17,7 +17,7 @@
         </encryption>
       </target>
     </disk>
-    <disk name='vdc' backup='yes' type='block'>
+    <disk name='vdc' backup='yes' type='block' backupmode='incremental' incremental='1525889631'>
       <driver type='qcow2'/>
       <target dev='/dev/block'>
         <encryption format='luks'>
index 59af3e6a6c9cdfaf829a114efb9d5b7b41b2705d..9a0d2b306139827a2b119e7e910f79ddf5239ebe 100644 (file)
@@ -1,13 +1,13 @@
 <domainbackup mode='push'>
   <incremental>1525889631</incremental>
   <disks>
-    <disk name='vda' backup='yes' type='file'>
+    <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'>
       <driver type='raw'/>
       <target file='/path/to/file'>
         <seclabel model='dac' relabel='no'/>
       </target>
     </disk>
-    <disk name='vdb' backup='yes' type='block'>
+    <disk name='vdb' backup='yes' type='block' backupmode='incremental' incremental='1525889631'>
       <driver type='qcow2'/>
       <target dev='/dev/block'>
         <seclabel model='dac' relabel='no'/>
index bc11a93d94792a17553286c5345c19c203734b38..317dcf6e471924855fd3e7c3acd3a76ee3da6d95 100644 (file)
@@ -1,7 +1,7 @@
 <domainbackup mode='push'>
   <incremental>1525889631</incremental>
   <disks>
-    <disk name='vda' backup='yes' type='file'>
+    <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'>
       <driver type='raw'/>
       <target file='/path/to/file'/>
     </disk>
index 52d2b4f0af50c247f3e852df29c8ad151b25052f..b1cbd154ab077c65b7f503b01d668d03a346b2bb 100644 (file)
@@ -1,6 +1,6 @@
 <domainbackup mode='push'>
   <disks>
-    <disk name='vdextradisk' backup='yes' type='file'>
+    <disk name='vdextradisk' backup='yes' type='file' backupmode='full'>
       <target file='/fake/vdextradisk.qcow2.SUFFIX'/>
     </disk>
   </disks>