From c9a1dfdb467c9873aa80eb75524e7fc74ce090e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 11 Dec 2024 23:33:35 -0500 Subject: [PATCH] incusd/storage/drivers/common: Truncate/Discard ahead of sparse write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we use a sparse writer which will skip any zero blocks, we need to discard (block) or truncate (file) prior to processing the data or we risk having leftover data from a previous snapshot interfere with the new state. Closes #1264 Signed-off-by: Stéphane Graber --- .../server/storage/drivers/generic_vfs.go | 13 +++++++ internal/server/storage/drivers/utils.go | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/internal/server/storage/drivers/generic_vfs.go b/internal/server/storage/drivers/generic_vfs.go index 7e38f540603..3816838f9bb 100644 --- a/internal/server/storage/drivers/generic_vfs.go +++ b/internal/server/storage/drivers/generic_vfs.go @@ -332,6 +332,12 @@ func genericVFSCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) ( defer func() { _ = to.Close() }() + // Reset the disk. + err = clearDiskData(path, to) + if err != nil { + return err + } + // Setup progress tracker. fromPipe := io.ReadCloser(conn) if wrapper != nil { @@ -787,6 +793,13 @@ func genericVFSBackupUnpack(d Driver, sysOS *sys.OS, vol Volume, snapshots []str logMsg = "Unpacking custom block volume" } + // Reset the disk. + err = clearDiskData(targetPath, to) + if err != nil { + return err + } + + // Copy the data. d.Logger().Debug(logMsg, logger.Ctx{"source": srcFile, "target": targetPath}) _, err = io.Copy(NewSparseFileWrapper(to), tr) if err != nil { diff --git a/internal/server/storage/drivers/utils.go b/internal/server/storage/drivers/utils.go index 36414dad473..67ea9f33a89 100644 --- a/internal/server/storage/drivers/utils.go +++ b/internal/server/storage/drivers/utils.go @@ -957,3 +957,38 @@ func roundAbove(above, val int64) int64 { return rounded } + +// clearDiskData resets a disk file or device to a zero value. +func clearDiskData(diskPath string, disk *os.File) error { + st, err := disk.Stat() + if err != nil { + return err + } + + if linux.IsBlockdev(st.Mode()) { + // If dealing with a block device, discard its current content. + // This saves space and avoids issues with leaving zero blocks to their original value. + _, err = subprocess.RunCommand("blkdiscard", diskPath) + if err != nil { + return err + } + } else { + // Otherwise truncate the file. + err = disk.Truncate(0) + if err != nil { + return err + } + + err = disk.Truncate(st.Size()) + if err != nil { + return err + } + + _, err = disk.Seek(0, 0) + if err != nil { + return err + } + } + + return nil +}