The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7131

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
As tarball creation will not create consistent backup when instance is running and files are being modified during backup, we avoid this by creating a snapshot of the main volume.

This is possible because ZFS allows us to create a snapshot quickly without freezing the main volume.
From bdf197028d9f5965fc602c24a22dc069cb899f29 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Fri, 3 Apr 2020 11:07:34 +0100
Subject: [PATCH] lxd/storage/drivers/driver/zfs/volumes: Create temporary
 snapshot in BackupVolume()

Ensures consistent backups when instance files are being modified during backup.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/driver_zfs_volumes.go | 49 +++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/lxd/storage/drivers/driver_zfs_volumes.go 
b/lxd/storage/drivers/driver_zfs_volumes.go
index d121254e0d..b8f1426b7e 100644
--- a/lxd/storage/drivers/driver_zfs_volumes.go
+++ b/lxd/storage/drivers/driver_zfs_volumes.go
@@ -1201,6 +1201,55 @@ func (d *zfs) BackupVolume(vol Volume, tarWriter 
*instancewriter.InstanceTarWrit
                        }
                }
 
+               // Because the generic backup method will not take a consistent 
backup if files are being modified
+               // as they are copied to the tarball, as ZFS allows us to take 
a quick snapshot without impacting
+               // the parent volume we do so here to ensure the backup taken 
is consistent.
+               if vol.contentType == ContentTypeFS {
+                       poolPath := GetPoolMountPath(d.name)
+                       tmpDir, err := ioutil.TempDir(poolPath, "backup.")
+                       if err != nil {
+                               return errors.Wrapf(err, "Failed to create 
temporary directory under %q", poolPath)
+                       }
+                       defer os.RemoveAll(tmpDir)
+
+                       err = os.Chmod(tmpDir, 0100)
+                       if err != nil {
+                               return errors.Wrapf(err, "Failed to chmod %q", 
tmpDir)
+                       }
+
+                       // Create a temporary snapshot.
+                       srcSnapshot := fmt.Sprintf("%s@backup-%s", 
d.dataset(vol, false), uuid.NewRandom().String())
+                       _, err = shared.RunCommand("zfs", "snapshot", 
srcSnapshot)
+                       if err != nil {
+                               return err
+                       }
+                       defer shared.RunCommand("zfs", "destroy", srcSnapshot)
+                       d.logger.Debug("Created backup snapshot", 
log.Ctx{"dev": srcSnapshot})
+
+                       // Override volume's mount path with location of 
snapshot so genericVFSBackupVolume reads
+                       // from there instead of main volume.
+                       vol.customMountPath = tmpDir
+
+                       // Mount the snapshot directly (not possible through 
ZFS tools), so that the volume is
+                       // already mounted by the time genericVFSBackupVolume 
tries to mount it below,
+                       // thus preventing it from trying to unmount it at the 
end, as this is a custom snapshot,
+                       // the normal mount and unmount logic will fail.
+                       err = TryMount(srcSnapshot, vol.MountPath(), "zfs", 0, 
"")
+                       if err != nil {
+                               return err
+                       }
+                       d.logger.Debug("Mounted ZFS snapshot dataset", 
log.Ctx{"dev": srcSnapshot, "path": vol.MountPath()})
+
+                       defer func(dataset string, mountPath string) {
+                               _, err := forceUnmount(mountPath)
+                               if err != nil {
+                                       return
+                               }
+
+                               d.logger.Debug("Unmounted ZFS snapshot 
dataset", log.Ctx{"dev": dataset, "path": mountPath})
+                       }(srcSnapshot, vol.MountPath())
+               }
+
                return genericVFSBackupVolume(d, vol, tarWriter, snapshots, op)
        }
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to