[lxc-devel] [lxd/master] patches: upgrade from LVM LXD instance with DIR containers

brauner on Github lxc-bot at linuxcontainers.org
Tue Mar 7 15:02:16 UTC 2017


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/20170307/058982a2/attachment.bin>
-------------- next part --------------
From 671166d83b3567b310084dd43314dff7b65cfa95 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 7 Mar 2017 12:44:44 +0100
Subject: [PATCH 1/2] lvm: dumb down functions from methods to functions

This way we can call them from other places as well.

Closes #3026.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_lvm.go | 137 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 79 insertions(+), 58 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 75b767c..25a44dd 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -391,8 +391,8 @@ func versionSplit(versionString string) (int, int, int, error) {
 	return maj, min, inc, nil
 }
 
-func (s *storageLvm) lvmVersionIsAtLeast(versionString string) (bool, error) {
-	lvmVersion := strings.Split(s.sTypeVersion, "/")[0]
+func lvmVersionIsAtLeast(sTypeVersion string, versionString string) (bool, error) {
+	lvmVersion := strings.Split(sTypeVersion, "/")[0]
 
 	lvmMaj, lvmMin, lvmInc, err := versionSplit(lvmVersion)
 	if err != nil {
@@ -716,7 +716,12 @@ func (s *storageLvm) StoragePoolVolumeCreate() error {
 		return err
 	}
 
-	err = s.createThinLV(poolName, thinPoolName, s.volume.Name, lvFsType, lvSize, volumeType)
+	err = lvmCreateThinpool(s.d, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+	if err != nil {
+		return err
+	}
+
+	err = lvmCreateThinLV(poolName, thinPoolName, s.volume.Name, lvFsType, lvSize, volumeType)
 	if err != nil {
 		shared.LogErrorf("LVMCreateThinLV: %s.", err)
 		return fmt.Errorf("Error Creating LVM LV for new image: %v", err)
@@ -1028,7 +1033,12 @@ func (s *storageLvm) ContainerCreate(container container) error {
 	}
 
 	poolName := s.getOnDiskPoolName()
-	err = s.createThinLV(poolName, thinPoolName, containerLvmName, lvFsType, lvSize, storagePoolVolumeApiEndpointContainers)
+	err = lvmCreateThinpool(s.d, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+	if err != nil {
+		return err
+	}
+
+	err = lvmCreateThinLV(poolName, thinPoolName, containerLvmName, lvFsType, lvSize, storagePoolVolumeApiEndpointContainers)
 	if err != nil {
 		return err
 	}
@@ -1741,7 +1751,12 @@ func (s *storageLvm) ImageCreate(fingerprint string) error {
 		}
 	}()
 
-	err = s.createThinLV(poolName, thinPoolName, fingerprint, lvFsType, lvSize, storagePoolVolumeApiEndpointImages)
+	err = lvmCreateThinpool(s.d, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+	if err != nil {
+		return err
+	}
+
+	err = lvmCreateThinLV(poolName, thinPoolName, fingerprint, lvFsType, lvSize, storagePoolVolumeApiEndpointImages)
 	if err != nil {
 		shared.LogErrorf("LVMCreateThinLV: %s.", err)
 		return fmt.Errorf("Error Creating LVM LV for new image: %v", err)
@@ -1856,25 +1871,72 @@ func (s *storageLvm) ImageUmount(fingerprint string) (bool, error) {
 	return true, nil
 }
 
-func (s *storageLvm) createThinLV(vgName string, thinPoolName string, lvName string, lvFsType string, lvSize string, volumeType string) error {
-	exists, err := storageLVMThinpoolExists(vgName, thinPoolName)
+func createDefaultThinPool(sTypeVersion string, vgName string, thinPoolName string, lvFsType string) error {
+	isRecent, err := lvmVersionIsAtLeast(sTypeVersion, "2.02.99")
 	if err != nil {
-		return err
+		return fmt.Errorf("Error checking LVM version: %s", err)
 	}
 
-	if !exists {
-		err := s.createDefaultThinPool(vgName, thinPoolName, lvName, lvFsType)
-		if err != nil {
-			return err
-		}
+	// Create the thin pool
+	lvmThinPool := fmt.Sprintf("%s/%s", vgName, thinPoolName)
+	var output []byte
+	if isRecent {
+		output, err = tryExec(
+			"lvcreate",
+			"--poolmetadatasize", "1G",
+			"-l", "100%FREE",
+			"--thinpool", lvmThinPool)
+	} else {
+		output, err = tryExec(
+			"lvcreate",
+			"--poolmetadatasize", "1G",
+			"-L", "1G",
+			"--thinpool", lvmThinPool)
+	}
+
+	if err != nil {
+		shared.LogErrorf("Could not create thin pool \"%s\": %s.", thinPoolName, string(output))
+		return fmt.Errorf("Could not create LVM thin pool named %s", thinPoolName)
+	}
+
+	if !isRecent {
+		// Grow it to the maximum VG size (two step process required by old LVM)
+		output, err = tryExec("lvextend", "--alloc", "anywhere", "-l", "100%FREE", lvmThinPool)
 
-		err = storageLVMValidateThinPoolName(s.d, vgName, thinPoolName)
 		if err != nil {
-			shared.LogErrorf("Setting thin pool name: %s.", err)
-			return fmt.Errorf("Error setting LVM thin pool config: %v", err)
+			shared.LogErrorf("Could not grow thin pool: \"%s\": %s.", thinPoolName, string(output))
+			return fmt.Errorf("Could not grow LVM thin pool named %s", thinPoolName)
 		}
 	}
 
+	return nil
+}
+
+func lvmCreateThinpool(d *Daemon, sTypeVersion string, vgName string, thinPoolName string, lvFsType string) error {
+	exists, err := storageLVMThinpoolExists(vgName, thinPoolName)
+	if err != nil {
+		return err
+	}
+
+	if exists {
+		return nil
+	}
+
+	err = createDefaultThinPool(sTypeVersion, vgName, thinPoolName, lvFsType)
+	if err != nil {
+		return err
+	}
+
+	err = storageLVMValidateThinPoolName(d, vgName, thinPoolName)
+	if err != nil {
+		shared.LogErrorf("Setting thin pool name: %s.", err)
+		return fmt.Errorf("Error setting LVM thin pool config: %v", err)
+	}
+
+	return nil
+}
+
+func lvmCreateThinLV(vgName string, thinPoolName string, lvName string, lvFsType string, lvSize string, volumeType string) error {
 	lvmThinPoolPath := fmt.Sprintf("%s/%s", vgName, thinPoolName)
 	lvmPoolVolumeName := getPrefixedLvName(volumeType, lvName)
 	output, err := tryExec(
@@ -1907,47 +1969,6 @@ func (s *storageLvm) createThinLV(vgName string, thinPoolName string, lvName str
 	return nil
 }
 
-func (s *storageLvm) createDefaultThinPool(vgName string, thinPoolName string, lvName string, lvFsType string) error {
-	isRecent, err := s.lvmVersionIsAtLeast("2.02.99")
-	if err != nil {
-		return fmt.Errorf("Error checking LVM version: %s", err)
-	}
-
-	// Create the thin pool
-	lvmThinPool := fmt.Sprintf("%s/%s", vgName, thinPoolName)
-	var output []byte
-	if isRecent {
-		output, err = tryExec(
-			"lvcreate",
-			"--poolmetadatasize", "1G",
-			"-l", "100%FREE",
-			"--thinpool", lvmThinPool)
-	} else {
-		output, err = tryExec(
-			"lvcreate",
-			"--poolmetadatasize", "1G",
-			"-L", "1G",
-			"--thinpool", lvmThinPool)
-	}
-
-	if err != nil {
-		shared.LogErrorf("Could not create thin pool \"%s\": %s.", thinPoolName, string(output))
-		return fmt.Errorf("Could not create LVM thin pool named %s", thinPoolName)
-	}
-
-	if !isRecent {
-		// Grow it to the maximum VG size (two step process required by old LVM)
-		output, err = tryExec("lvextend", "--alloc", "anywhere", "-l", "100%FREE", lvmThinPool)
-
-		if err != nil {
-			shared.LogErrorf("Could not grow thin pool: \"%s\": %s.", thinPoolName, string(output))
-			return fmt.Errorf("Could not grow LVM thin pool named %s", thinPoolName)
-		}
-	}
-
-	return nil
-}
-
 func (s *storageLvm) removeLV(vgName string, volumeType string, lvName string) error {
 	lvmVolumePath := getLvmDevPath(vgName, volumeType, lvName)
 	output, err := tryExec("lvremove", "-f", lvmVolumePath)
@@ -1963,7 +1984,7 @@ func (s *storageLvm) removeLV(vgName string, volumeType string, lvName string) e
 func (s *storageLvm) createSnapshotLV(vgName string, origLvName string, origVolumeType string, lvName string, volumeType string, readonly bool) (string, error) {
 	sourceLvmVolumePath := getLvmDevPath(vgName, origVolumeType, origLvName)
 	shared.LogDebugf("in createSnapshotLV: %s.", sourceLvmVolumePath)
-	isRecent, err := s.lvmVersionIsAtLeast("2.02.99")
+	isRecent, err := lvmVersionIsAtLeast(s.sTypeVersion, "2.02.99")
 	if err != nil {
 		return "", fmt.Errorf("Error checking LVM version: %v", err)
 	}

From aa2fe123504b0e432897dc768aea06769822b5d9 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 7 Mar 2017 15:43:59 +0100
Subject: [PATCH 2/2] patches: handle mixed-storage <lvm,dir> upgrade

Handle the case where we have a LVM upgrade that has DIR containers.

Closes #3026.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/patches.go     | 230 ++++++++++++++++++++++++++++++++++++++++++-----------
 lxd/storage_lvm.go |   7 ++
 2 files changed, 191 insertions(+), 46 deletions(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index 369860b..d522fc6 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -827,7 +827,15 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		poolConfig["volume.block.mount_options"] = fsMntOpts
 	}
 
+	thinPoolName := "LXDPool"
 	poolConfig["lvm.thinpool_name"] = daemonConfig["storage.lvm_thinpool_name"].Get()
+	if poolConfig["lvm.thinpool_name"] != "" {
+		thinPoolName = poolConfig["lvm.thinpool_name"]
+	} else {
+		// If empty we need to set it to the old default.
+		poolConfig["lvm.thinpool_name"] = thinPoolName
+	}
+
 	poolConfig["lvm.vg_name"] = daemonConfig["storage.lvm_vg_name"].Get()
 
 	poolConfig["volume.size"] = daemonConfig["storage.lvm_volume_size"].Get()
@@ -897,6 +905,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		return err
 	}
 
+	// Create pool mountpoint if it doesn't already exist.
 	poolMntPoint := getStoragePoolMountPoint(defaultPoolName)
 	if !shared.PathExists(poolMntPoint) {
 		err = os.MkdirAll(poolMntPoint, 0711)
@@ -906,6 +915,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 	}
 
 	if len(cRegular) > 0 {
+		// Create generic containers folder on the storage pool.
 		newContainersMntPoint := getContainerMountPoint(defaultPoolName, "")
 		if !shared.PathExists(newContainersMntPoint) {
 			err = os.MkdirAll(newContainersMntPoint, 0711)
@@ -955,6 +965,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		if shared.IsMountPoint(oldContainerMntPoint) {
 			err := tryUnmount(oldContainerMntPoint, syscall.MNT_DETACH)
 			if err != nil {
+				shared.LogErrorf("Failed to unmount LVM logical volume \"%s\": %s.", oldContainerMntPoint, err)
 				return err
 			}
 		}
@@ -963,28 +974,91 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		// new storage api. We do os.Rename() here to preserve
 		// permissions and ownership.
 		newContainerMntPoint := getContainerMountPoint(defaultPoolName, ct)
-		if shared.PathExists(oldContainerMntPoint) && !shared.PathExists(newContainerMntPoint) {
-			err = os.Rename(oldContainerMntPoint, newContainerMntPoint)
-			if err != nil {
-				return err
-			}
-		}
-
-		if shared.PathExists(oldContainerMntPoint + ".lv") {
-			err := os.Remove(oldContainerMntPoint + ".lv")
-			if err != nil {
-				return err
-			}
-		}
-
-		// Rename the logical volume device.
 		ctLvName := containerNameToLVName(ct)
 		newContainerLvName := fmt.Sprintf("%s_%s", storagePoolVolumeApiEndpointContainers, ctLvName)
 		containerLvDevPath := getLvmDevPath(defaultPoolName, storagePoolVolumeApiEndpointContainers, ctLvName)
 		if !shared.PathExists(containerLvDevPath) {
-			_, err := tryExec("lvrename", defaultPoolName, ctLvName, newContainerLvName)
-			if err != nil {
-				return err
+			oldLvDevPath := fmt.Sprintf("/dev/%s/%s", defaultPoolName, ctLvName)
+			// If the old LVM device path for the logical volume
+			// exists we call lvrename. Otherwise this is likely a
+			// mixed-storage LXD instance which we need to deal
+			// with.
+			if shared.PathExists(oldLvDevPath) {
+				// Rename the logical volume mountpoint.
+				if shared.PathExists(oldContainerMntPoint) && !shared.PathExists(newContainerMntPoint) {
+					err = os.Rename(oldContainerMntPoint, newContainerMntPoint)
+					if err != nil {
+						shared.LogErrorf("Failed to rename LVM container mountpoint from %s to %s: %s.", oldContainerMntPoint, newContainerMntPoint, err)
+						return err
+					}
+				}
+
+				// Remove the old container mountpoint.
+				if shared.PathExists(oldContainerMntPoint + ".lv") {
+					err := os.Remove(oldContainerMntPoint + ".lv")
+					if err != nil {
+						shared.LogErrorf("Failed to remove old LVM container mountpoint %s: %s.", oldContainerMntPoint+".lv", err)
+						return err
+					}
+				}
+
+				// Rename the logical volume.
+				msg, err := tryExec("lvrename", defaultPoolName, ctLvName, newContainerLvName)
+				if err != nil {
+					shared.LogErrorf("Failed to rename LVM logical volume from %s to %s: %s.", ctLvName, newContainerLvName, msg)
+					return err
+				}
+			} else if shared.PathExists(oldContainerMntPoint) && shared.IsDir(oldContainerMntPoint) {
+				// This is a directory backed container and it
+				// means that this was a mixed-storage LXD
+				// instance.
+
+				// Initialize storage interface for the new
+				// container.
+				ctStorage, err := storagePoolVolumeContainerLoadInit(d, ct)
+				if err != nil {
+					shared.LogErrorf("Failed to initialize new storage interface for LVM container %s: %s.", ct, err)
+					return err
+				}
+
+				// Load the container from the database.
+				ctStruct, err := containerLoadByName(d, ct)
+				if err != nil {
+					shared.LogErrorf("Failed to load LVM container %s: %s.", ct, err)
+					return err
+				}
+
+				// Create an empty LVM logical volume for the
+				// container.
+				err = ctStorage.ContainerCreate(ctStruct)
+				if err != nil {
+					shared.LogErrorf("Failed to create empty LVM logical volume for container %s: %s.", ct, err)
+					return err
+				}
+
+				// In case the new LVM logical volume for the
+				// container is not mounted mount it.
+				if !shared.IsMountPoint(newContainerMntPoint) {
+					_, err = ctStorage.ContainerMount(ctStruct.Name(), ctStruct.Path())
+					if err != nil {
+						shared.LogErrorf("Failed to mount new empty LVM logical volume for container %s: %s.", ct, err)
+						return err
+					}
+				}
+
+				// Use rsync to fill the empty volume.
+				output, err := storageRsyncCopy(oldContainerMntPoint, newContainerMntPoint)
+				if err != nil {
+					ctStorage.ContainerDelete(ctStruct)
+					return fmt.Errorf("rsync failed: %s", string(output))
+				}
+
+				// Remove the old container.
+				err = os.RemoveAll(oldContainerMntPoint)
+				if err != nil {
+					shared.LogErrorf("Failed to remove old container %s: %s.", oldContainerMntPoint, err)
+					return err
+				}
 			}
 		}
 
@@ -992,6 +1066,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		doesntMatter := false
 		err = createContainerMountpoint(newContainerMntPoint, oldContainerMntPoint, doesntMatter)
 		if err != nil {
+			shared.LogErrorf("Failed to create container mountpoint \"%s\" for LVM logical volume: %s.", newContainerMntPoint, err)
 			return err
 		}
 
@@ -1003,13 +1078,6 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 			mountOptions = "discard"
 		}
 
-		if !shared.IsMountPoint(newContainerMntPoint) {
-			err := tryMount(containerLvDevPath, newContainerMntPoint, lvFsType, 0, mountOptions)
-			if err != nil {
-				return err
-			}
-		}
-
 		// Check if we need to account for snapshots for this container.
 		ctSnapshots, err := dbContainerGetSnapshots(d.db, ct)
 		if err != nil {
@@ -1058,24 +1126,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 				}
 			}
 
-			// Unmount the logical volume.
 			oldSnapshotMntPoint := shared.VarPath("snapshots", cs)
-			if shared.IsMountPoint(oldSnapshotMntPoint) {
-				err := tryUnmount(oldSnapshotMntPoint, syscall.MNT_DETACH)
-				if err != nil {
-					return err
-				}
-			}
-
-			// Rename the snapshot mountpoint to preserve acl's and
-			// so on.
-			if shared.PathExists(oldSnapshotMntPoint) && !shared.PathExists(newSnapshotMntPoint) {
-				err := os.Rename(oldSnapshotMntPoint, newSnapshotMntPoint)
-				if err != nil {
-					return err
-				}
-			}
-
 			os.Remove(oldSnapshotMntPoint + ".lv")
 
 			// Make sure we use a valid lv name.
@@ -1083,9 +1134,85 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 			newSnapshotLvName := fmt.Sprintf("%s_%s", storagePoolVolumeApiEndpointContainers, csLvName)
 			snapshotLvDevPath := getLvmDevPath(defaultPoolName, storagePoolVolumeApiEndpointContainers, csLvName)
 			if !shared.PathExists(snapshotLvDevPath) {
-				_, err := tryExec("lvrename", defaultPoolName, csLvName, newSnapshotLvName)
-				if err != nil {
-					return err
+				oldLvDevPath := fmt.Sprintf("/dev/%s/%s", defaultPoolName, csLvName)
+				if shared.PathExists(oldLvDevPath) {
+					// Unmount the logical volume.
+					if shared.IsMountPoint(oldSnapshotMntPoint) {
+						err := tryUnmount(oldSnapshotMntPoint, syscall.MNT_DETACH)
+						if err != nil {
+							shared.LogErrorf("Failed to unmount LVM logical volume \"%s\": %s.", oldSnapshotMntPoint, err)
+							return err
+						}
+					}
+
+					// Rename the snapshot mountpoint to preserve acl's and
+					// so on.
+					if shared.PathExists(oldSnapshotMntPoint) && !shared.PathExists(newSnapshotMntPoint) {
+						err := os.Rename(oldSnapshotMntPoint, newSnapshotMntPoint)
+						if err != nil {
+							shared.LogErrorf("Failed to rename LVM container mountpoint from %s to %s: %s.", oldSnapshotMntPoint, newSnapshotMntPoint, err)
+							return err
+						}
+					}
+
+					// Rename the logical volume.
+					msg, err := tryExec("lvrename", defaultPoolName, csLvName, newSnapshotLvName)
+					if err != nil {
+						shared.LogErrorf("Failed to rename LVM logical volume from %s to %s: %s.", csLvName, newSnapshotLvName, msg)
+						return err
+					}
+				} else if shared.PathExists(oldSnapshotMntPoint) && shared.IsDir(oldSnapshotMntPoint) {
+					// This is a directory backed container
+					// and it means that this was a
+					// mixed-storage LXD instance.
+
+					// Initialize storage interface for the new
+					// snapshot.
+					csStorage, err := storagePoolVolumeContainerLoadInit(d, cs)
+					if err != nil {
+						shared.LogErrorf("Failed to initialize new storage interface for LVM container %s: %s.", cs, err)
+						return err
+					}
+
+					// Load the snapshot from the database.
+					csStruct, err := containerLoadByName(d, cs)
+					if err != nil {
+						shared.LogErrorf("Failed to load LVM container %s: %s.", cs, err)
+						return err
+					}
+
+					// Create an empty LVM logical volume
+					// for the snapshot.
+					err = csStorage.ContainerSnapshotCreateEmpty(csStruct)
+					if err != nil {
+						shared.LogErrorf("Failed to create empty LVM logical volume for container %s: %s.", cs, err)
+						return err
+					}
+
+					// In case the new LVM logical volume
+					// for the snapshot is not mounted mount
+					// it.
+					if !shared.IsMountPoint(newSnapshotMntPoint) {
+						_, err = csStorage.ContainerMount(csStruct.Name(), csStruct.Path())
+						if err != nil {
+							shared.LogErrorf("Failed to mount new empty LVM logical volume for container %s: %s.", cs, err)
+							return err
+						}
+					}
+
+					// Use rsync to fill the empty volume.
+					output, err := storageRsyncCopy(oldSnapshotMntPoint, newSnapshotMntPoint)
+					if err != nil {
+						csStorage.ContainerDelete(csStruct)
+						return fmt.Errorf("rsync failed: %s", string(output))
+					}
+
+					// Remove the old snapshot.
+					err = os.RemoveAll(oldSnapshotMntPoint)
+					if err != nil {
+						shared.LogErrorf("Failed to remove old container %s: %s.", oldSnapshotMntPoint, err)
+						return err
+					}
 				}
 			}
 		}
@@ -1113,6 +1240,13 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 			}
 		}
 
+		if !shared.IsMountPoint(newContainerMntPoint) {
+			err := tryMount(containerLvDevPath, newContainerMntPoint, lvFsType, 0, mountOptions)
+			if err != nil {
+				shared.LogErrorf("Failed to mount LVM logical \"%s\" onto \"%s\" : %s.", containerLvDevPath, newContainerMntPoint, err)
+				return err
+			}
+		}
 	}
 
 	images := append(imgPublic, imgPrivate...)
@@ -1179,7 +1313,11 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		// Rename the logical volume device.
 		newImageLvName := fmt.Sprintf("%s_%s", storagePoolVolumeApiEndpointImages, img)
 		imageLvDevPath := getLvmDevPath(defaultPoolName, storagePoolVolumeApiEndpointImages, img)
-		if !shared.PathExists(imageLvDevPath) {
+		oldLvDevPath := fmt.Sprintf("/dev/%s/%s", defaultPoolName, img)
+		// Only create logical volumes for images that have a logical
+		// volume on the pre-storage-api LXD instance. If not, we don't
+		// care since LXD will create a logical volume on demand.
+		if !shared.PathExists(imageLvDevPath) && shared.PathExists(oldLvDevPath) {
 			_, err := tryExec("lvrename", defaultPoolName, img, newImageLvName)
 			if err != nil {
 				return err
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 25a44dd..388deb3 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -1321,7 +1321,11 @@ func (s *storageLvm) ContainerMount(name string, path string) (bool, error) {
 	poolName := s.getOnDiskPoolName()
 	containerLvmPath := getLvmDevPath(poolName, storagePoolVolumeApiEndpointContainers, containerLvmName)
 	mountOptions := s.getLvmBlockMountOptions()
+
 	containerMntPoint := getContainerMountPoint(s.pool.Name, name)
+	if shared.IsSnapshot(name) {
+		containerMntPoint = getSnapshotMountPoint(s.pool.Name, name)
+	}
 
 	containerMountLockID := getContainerMountLockID(s.pool.Name, name)
 	lxdStorageMapLock.Lock()
@@ -1364,6 +1368,9 @@ func (s *storageLvm) ContainerUmount(name string, path string) (bool, error) {
 	shared.LogDebugf("Unmounting LVM storage volume for container \"%s\" on storage pool \"%s\".", s.volume.Name, s.pool.Name)
 
 	containerMntPoint := getContainerMountPoint(s.pool.Name, name)
+	if shared.IsSnapshot(name) {
+		containerMntPoint = getSnapshotMountPoint(s.pool.Name, name)
+	}
 
 	containerUmountLockID := getContainerUmountLockID(s.pool.Name, name)
 	lxdStorageMapLock.Lock()


More information about the lxc-devel mailing list