[lxc-devel] [lxd/master] Storage fixes and cleanups

stgraber on Github lxc-bot at linuxcontainers.org
Tue Dec 17 21:35:11 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191217/43f3eda1/attachment.bin>
-------------- next part --------------
From 2c9315386c40b2cc3df60bce5de507130999bbdf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 12:30:35 -0500
Subject: [PATCH 1/7] lxd/storage/cephfs: Use common functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/drivers/driver_cephfs_volumes.go | 63 +-------------------
 1 file changed, 2 insertions(+), 61 deletions(-)

diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go
index 337cade4cd..9c04180f43 100644
--- a/lxd/storage/drivers/driver_cephfs_volumes.go
+++ b/lxd/storage/drivers/driver_cephfs_volumes.go
@@ -3,7 +3,6 @@ package drivers
 import (
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -433,39 +432,7 @@ func (d *cephfs) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs m
 		return fmt.Errorf("Migration type not supported")
 	}
 
-	bwlimit := d.config["rsync.bwlimit"]
-
-	for _, snapName := range volSrcArgs.Snapshots {
-		snapshot, err := vol.NewSnapshot(snapName)
-		if err != nil {
-			return err
-		}
-
-		// Send snapshot to recipient (ensure local snapshot volume is mounted if needed).
-		err = snapshot.MountTask(func(mountPath string, op *operations.Operation) error {
-			var wrapper *ioprogress.ProgressTracker
-			if volSrcArgs.TrackProgress {
-				wrapper = migration.ProgressTracker(op, "fs_progress", snapshot.name)
-			}
-
-			path := shared.AddSlash(mountPath)
-			return rsync.Send(snapshot.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath)
-		}, op)
-		if err != nil {
-			return err
-		}
-	}
-
-	// Send volume to recipient (ensure local volume is mounted if needed).
-	return vol.MountTask(func(mountPath string, op *operations.Operation) error {
-		var wrapper *ioprogress.ProgressTracker
-		if volSrcArgs.TrackProgress {
-			wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
-		}
-
-		path := shared.AddSlash(mountPath)
-		return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath)
-	}, op)
+	return d.vfsMigrateVolume(vol, conn, volSrcArgs, op)
 }
 
 // BackupVolume creates an exported version of a volume.
@@ -536,33 +503,7 @@ func (d *cephfs) UnmountVolumeSnapshot(snapVol Volume, op *operations.Operation)
 
 // VolumeSnapshots returns a list of snapshot names for the volume.
 func (d *cephfs) VolumeSnapshots(vol Volume, op *operations.Operation) ([]string, error) {
-	snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name)
-	snapshots := []string{}
-
-	ents, err := ioutil.ReadDir(snapshotDir)
-	if err != nil {
-		// If the snapshots directory doesn't exist, there are no snapshots.
-		if os.IsNotExist(err) {
-			return snapshots, nil
-		}
-
-		return nil, err
-	}
-
-	for _, ent := range ents {
-		fileInfo, err := os.Stat(filepath.Join(snapshotDir, ent.Name()))
-		if err != nil {
-			return nil, err
-		}
-
-		if !fileInfo.IsDir() {
-			continue
-		}
-
-		snapshots = append(snapshots, ent.Name())
-	}
-
-	return snapshots, nil
+	return d.vfsVolumeSnapshots(vol, op)
 }
 
 // RestoreVolume resets a volume to its snapshotted state.

From 6fd3b2befd0356df892917ef02cc0ee0c60ab885 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 14:00:37 -0500
Subject: [PATCH 2/7] lxd/storage/common: Add vfsHasVolume
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/drivers/driver_cephfs_volumes.go |  6 +-----
 lxd/storage/drivers/driver_common.go         | 10 ++++++++++
 lxd/storage/drivers/driver_dir_volumes.go    |  6 +-----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go
index 9c04180f43..776bd42231 100644
--- a/lxd/storage/drivers/driver_cephfs_volumes.go
+++ b/lxd/storage/drivers/driver_cephfs_volumes.go
@@ -262,11 +262,7 @@ func (d *cephfs) DeleteVolume(vol Volume, op *operations.Operation) error {
 
 // HasVolume indicates whether a specific volume exists on the storage pool.
 func (d *cephfs) HasVolume(vol Volume) bool {
-	if shared.PathExists(vol.MountPath()) {
-		return true
-	}
-
-	return false
+	return d.vfsHasVolume(vol)
 }
 
 // ValidateVolume validates the supplied volume config.
diff --git a/lxd/storage/drivers/driver_common.go b/lxd/storage/drivers/driver_common.go
index e2e44ccb3e..a55047cefd 100644
--- a/lxd/storage/drivers/driver_common.go
+++ b/lxd/storage/drivers/driver_common.go
@@ -219,6 +219,7 @@ func (d *common) vfsRenameVolumeSnapshot(snapVol Volume, newSnapshotName string,
 	return nil
 }
 
+// vfsMigrateVolume is a generic MigrateVolume implementation for VFS-only drivers.
 func (d *common) vfsMigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, op *operations.Operation) error {
 	bwlimit := d.config["rsync.bwlimit"]
 
@@ -254,3 +255,12 @@ func (d *common) vfsMigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArg
 		return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath)
 	}, op)
 }
+
+// vfsHasVolume is a generic HasVolume implementation for VFS-only drivers.
+func (d *common) vfsHasVolume(vol Volume) bool {
+	if shared.PathExists(vol.MountPath()) {
+		return true
+	}
+
+	return false
+}
diff --git a/lxd/storage/drivers/driver_dir_volumes.go b/lxd/storage/drivers/driver_dir_volumes.go
index d36a0d8bef..000acee849 100644
--- a/lxd/storage/drivers/driver_dir_volumes.go
+++ b/lxd/storage/drivers/driver_dir_volumes.go
@@ -386,11 +386,7 @@ func (d *dir) DeleteVolume(vol Volume, op *operations.Operation) error {
 
 // HasVolume indicates whether a specific volume exists on the storage pool.
 func (d *dir) HasVolume(vol Volume) bool {
-	if shared.PathExists(vol.MountPath()) {
-		return true
-	}
-
-	return false
+	return d.vfsHasVolume(vol)
 }
 
 // ValidateVolume validates the supplied volume config.

From fb7b54c4ed70eed18d345b8ad920e3797cf48067 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 14:11:42 -0500
Subject: [PATCH 3/7] lxd/storage/common: Add vfsGetVolumeDiskPath
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/drivers/driver_common.go      | 9 +++++++++
 lxd/storage/drivers/driver_dir_volumes.go | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/driver_common.go b/lxd/storage/drivers/driver_common.go
index a55047cefd..5f9ce8560b 100644
--- a/lxd/storage/drivers/driver_common.go
+++ b/lxd/storage/drivers/driver_common.go
@@ -264,3 +264,12 @@ func (d *common) vfsHasVolume(vol Volume) bool {
 
 	return false
 }
+
+// vfsGetVolumeDiskPath is a generic GetVolumeDiskPath implementation for VFS-only drivers.
+func (d *common) vfsGetVolumeDiskPath(vol Volume) (string, error) {
+	if vol.contentType != ContentTypeBlock {
+		return "", fmt.Errorf("No disk paths for filesystems")
+	}
+
+	return filepath.Join(vol.MountPath(), "root.img"), nil
+}
diff --git a/lxd/storage/drivers/driver_dir_volumes.go b/lxd/storage/drivers/driver_dir_volumes.go
index 000acee849..acbc6b2a79 100644
--- a/lxd/storage/drivers/driver_dir_volumes.go
+++ b/lxd/storage/drivers/driver_dir_volumes.go
@@ -454,7 +454,7 @@ func (d *dir) SetVolumeQuota(vol Volume, size string, op *operations.Operation)
 
 // GetVolumeDiskPath returns the location of a disk volume.
 func (d *dir) GetVolumeDiskPath(vol Volume) (string, error) {
-	return filepath.Join(vol.MountPath(), "root.img"), nil
+	return d.vfsGetVolumeDiskPath(vol)
 }
 
 // MountVolume simulates mounting a volume. As dir driver doesn't have volumes to mount it returns

From 713d8bd692204591eec70d013d30145f840cac30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 15:07:41 -0500
Subject: [PATCH 4/7] lxd/storage: Always init driver with state/logger
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/utils.go   | 10 +++++++---
 lxd/storage_volumes.go |  4 ++--
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
index 0ccd6b0a4f..bcd370f3f0 100644
--- a/lxd/storage/utils.go
+++ b/lxd/storage/utils.go
@@ -17,7 +17,9 @@ import (
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 	"github.com/lxc/lxd/shared/ioprogress"
+	log "github.com/lxc/lxd/shared/log15"
 	"github.com/lxc/lxd/shared/logger"
+	"github.com/lxc/lxd/shared/logging"
 	"github.com/lxc/lxd/shared/units"
 )
 
@@ -384,7 +386,7 @@ func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescrip
 	}
 
 	// Validate the requested storage volume configuration.
-	err = VolumeValidateConfig(poolName, volumeConfig, poolStruct)
+	err = VolumeValidateConfig(s, poolName, volumeConfig, poolStruct)
 	if err != nil {
 		return err
 	}
@@ -464,9 +466,11 @@ var StorageVolumeConfigKeys = map[string]func(value string) ([]string, error){
 }
 
 // VolumeValidateConfig validations volume config. Deprecated.
-func VolumeValidateConfig(name string, config map[string]string, parentPool *api.StoragePool) error {
+func VolumeValidateConfig(s *state.State, name string, config map[string]string, parentPool *api.StoragePool) error {
+	logger := logging.AddContext(logger.Log, log.Ctx{"driver": parentPool.Driver, "pool": parentPool.Name})
+
 	// Validate volume config using the new driver interface if supported.
-	driver, err := drivers.Load(nil, parentPool.Driver, parentPool.Name, parentPool.Config, nil, nil, validateVolumeCommonRules)
+	driver, err := drivers.Load(s, parentPool.Driver, parentPool.Name, parentPool.Config, logger, nil, validateVolumeCommonRules)
 	if err != drivers.ErrUnknownDriver {
 		// Note: This legacy validation function doesn't have the concept of validating
 		// different volumes types, so the types are hard coded as Custom and FS.
diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index f6636c0482..6748d3f2b7 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -1039,7 +1039,7 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string)
 			}
 		} else {
 			// Validate the configuration
-			err = storagePools.VolumeValidateConfig(volumeName, req.Config, poolRow)
+			err = storagePools.VolumeValidateConfig(d.State(), volumeName, req.Config, poolRow)
 			if err != nil {
 				return response.BadRequest(err)
 			}
@@ -1153,7 +1153,7 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName strin
 		}
 	} else {
 		// Validate the configuration.
-		err = storagePools.VolumeValidateConfig(volumeName, req.Config, poolRow)
+		err = storagePools.VolumeValidateConfig(d.State(), volumeName, req.Config, poolRow)
 		if err != nil {
 			return response.BadRequest(err)
 		}

From 25e92d23603e341475680e5b854ea92a9f820c16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 16:29:00 -0500
Subject: [PATCH 5/7] lxd/storage: Replace CreateMountPath with EnsureMountPath
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/drivers/driver_cephfs_volumes.go | 10 ++++++----
 lxd/storage/drivers/driver_dir_utils.go      |  2 +-
 lxd/storage/drivers/driver_dir_volumes.go    |  8 ++++----
 lxd/storage/drivers/volume.go                | 21 +++++++++++---------
 4 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go
index 776bd42231..c021acfae6 100644
--- a/lxd/storage/drivers/driver_cephfs_volumes.go
+++ b/lxd/storage/drivers/driver_cephfs_volumes.go
@@ -25,13 +25,14 @@ func (d *cephfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.O
 		return fmt.Errorf("Content type not supported")
 	}
 
+	// Create the main volume path.
 	volPath := vol.MountPath()
-
-	err := os.MkdirAll(volPath, 0711)
+	err := vol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
 
+	// Setup for revert.
 	revertPath := true
 	defer func() {
 		if revertPath {
@@ -39,6 +40,7 @@ func (d *cephfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.O
 		}
 	}()
 
+	// Fill the volume.
 	if filler != nil && filler.Fill != nil {
 		d.logger.Debug("Running filler function")
 		err = filler.Fill(volPath, "")
@@ -62,7 +64,7 @@ func (d *cephfs) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots b
 
 	// Create the main volume path.
 	volPath := vol.MountPath()
-	err := vol.CreateMountPath()
+	err := vol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
@@ -144,7 +146,7 @@ func (d *cephfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser,
 
 	// Create the main volume path.
 	volPath := vol.MountPath()
-	err := vol.CreateMountPath()
+	err := vol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
diff --git a/lxd/storage/drivers/driver_dir_utils.go b/lxd/storage/drivers/driver_dir_utils.go
index 868c9a91dd..1ba9dcfdca 100644
--- a/lxd/storage/drivers/driver_dir_utils.go
+++ b/lxd/storage/drivers/driver_dir_utils.go
@@ -28,7 +28,7 @@ func (d *dir) copyVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *o
 
 	// Create the main volume path.
 	volPath := vol.MountPath()
-	err = vol.CreateMountPath()
+	err = vol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
diff --git a/lxd/storage/drivers/driver_dir_volumes.go b/lxd/storage/drivers/driver_dir_volumes.go
index acbc6b2a79..e664f8fd07 100644
--- a/lxd/storage/drivers/driver_dir_volumes.go
+++ b/lxd/storage/drivers/driver_dir_volumes.go
@@ -20,7 +20,7 @@ import (
 // filler function.
 func (d *dir) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error {
 	volPath := vol.MountPath()
-	err := vol.CreateMountPath()
+	err := vol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
@@ -123,7 +123,7 @@ func (d *dir) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.
 	}()
 
 	volPath := vol.MountPath()
-	err := vol.CreateMountPath()
+	err := vol.EnsureMountPath()
 	if err != nil {
 		return nil, nil, err
 	}
@@ -222,7 +222,7 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 
 	// Create the main volume path.
 	volPath := vol.MountPath()
-	err = vol.CreateMountPath()
+	err = vol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
@@ -552,7 +552,7 @@ func (d *dir) CreateVolumeSnapshot(snapVol Volume, op *operations.Operation) err
 	}
 
 	// Create snapshot directory.
-	err = snapVol.CreateMountPath()
+	err = snapVol.EnsureMountPath()
 	if err != nil {
 		return err
 	}
diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
index fff2150178..cd1ff93746 100644
--- a/lxd/storage/drivers/volume.go
+++ b/lxd/storage/drivers/volume.go
@@ -89,23 +89,26 @@ func (v Volume) MountPath() string {
 	return GetVolumeMountPath(v.pool, v.volType, v.name)
 }
 
-// CreateMountPath creates the volume's mount path and sets the correct permission for the type.
-func (v Volume) CreateMountPath() error {
+// EnsureMountPath creates the volume's mount path if missing, then sets the correct permission for the type.
+func (v Volume) EnsureMountPath() error {
 	volPath := v.MountPath()
 
 	// Create volume's mount path, with any created directories set to 0711.
-	err := os.MkdirAll(volPath, 0711)
-	if err != nil {
+	err := os.Mkdir(volPath, 0711)
+	if err != nil && !os.IsExist(err) {
 		return err
 	}
 
 	// Set very restrictive mode 0100 for non-custom and non-image volumes.
+	mode := os.FileMode(0711)
 	if v.volType != VolumeTypeCustom && v.volType != VolumeTypeImage {
-		// Set mode of actual volume's mount path.
-		err = os.Chmod(volPath, 0100)
-		if err != nil {
-			return err
-		}
+		mode = os.FileMode(0100)
+	}
+
+	// Set mode of actual volume's mount path.
+	err = os.Chmod(volPath, mode)
+	if err != nil {
+		return err
 	}
 
 	return nil

From 05c99fd684a0c4c6ee3a5558b86cdeb176316869 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 16:29:28 -0500
Subject: [PATCH 6/7] lxd/storage/cephfs: Use helper functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/drivers/driver_cephfs_volumes.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lxd/storage/drivers/driver_cephfs_volumes.go b/lxd/storage/drivers/driver_cephfs_volumes.go
index c021acfae6..b0dde7aadd 100644
--- a/lxd/storage/drivers/driver_cephfs_volumes.go
+++ b/lxd/storage/drivers/driver_cephfs_volumes.go
@@ -329,10 +329,8 @@ func (d *cephfs) UnmountVolume(vol Volume, op *operations.Operation) (bool, erro
 
 // RenameVolume renames the volume and all related filesystem entries.
 func (d *cephfs) RenameVolume(vol Volume, newName string, op *operations.Operation) error {
-	// Create new snapshots directory.
-	snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, newName)
-
-	err := os.MkdirAll(snapshotDir, 0711)
+	// Create the parent directory.
+	err := createParentSnapshotDirIfMissing(d.name, vol.volType, newName)
 	if err != nil {
 		return err
 	}
@@ -357,6 +355,7 @@ func (d *cephfs) RenameVolume(vol Volume, newName string, op *operations.Operati
 
 		// Remove the new snapshot directory if we are reverting.
 		if len(revertPaths) > 0 {
+			snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, newName)
 			err = os.RemoveAll(snapshotDir)
 		}
 	}()
@@ -451,13 +450,14 @@ func (d *cephfs) CreateVolumeSnapshot(snapVol Volume, op *operations.Operation)
 		return err
 	}
 
-	targetPath := snapVol.MountPath()
-
-	err = os.MkdirAll(filepath.Dir(targetPath), 0711)
+	// Create the parent directory.
+	err = createParentSnapshotDirIfMissing(d.name, snapVol.volType, parentName)
 	if err != nil {
 		return err
 	}
 
+	// Create the symlink.
+	targetPath := snapVol.MountPath()
 	err = os.Symlink(cephSnapPath, targetPath)
 	if err != nil {
 		return err

From ad10d6b65dda6237a4a2a15d9cb57c0c28df5e29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 17 Dec 2019 16:33:19 -0500
Subject: [PATCH 7/7] lxd/storage/dir: Use helper functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage/drivers/driver_dir_volumes.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage/drivers/driver_dir_volumes.go b/lxd/storage/drivers/driver_dir_volumes.go
index e664f8fd07..35d04b8dd8 100644
--- a/lxd/storage/drivers/driver_dir_volumes.go
+++ b/lxd/storage/drivers/driver_dir_volumes.go
@@ -153,12 +153,12 @@ func (d *dir) CreateVolumeFromBackup(vol Volume, snapshots []string, srcData io.
 
 	if len(snapshots) > 0 {
 		// Create new snapshots directory.
-		snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name)
-		err := os.MkdirAll(snapshotDir, 0711)
+		err := createParentSnapshotDirIfMissing(d.name, vol.volType, vol.name)
 		if err != nil {
 			return nil, nil, err
 		}
 
+		snapshotDir := GetVolumeSnapshotDir(d.name, vol.volType, vol.name)
 		revertPaths = append(revertPaths, snapshotDir)
 
 		// Prepare tar arguments.


More information about the lxc-devel mailing list