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