[lxc-devel] [lxd/master] Storage: Regenerate cached image volumes when cannot be shrunk

tomponline on Github lxc-bot at linuxcontainers.org
Wed Apr 22 11:21:28 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1321 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200422/2601b470/attachment-0001.bin>
-------------- next part --------------
From ddcc2a1d5bafb30cf3e9f12e64ac1586d2a11886 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 22 Apr 2020 11:40:36 +0100
Subject: [PATCH 1/5] lxd/storage/backend/lxd: Updates CreateInstanceFromImage
 to use reverter

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_lxd.go | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 9308304b26..497e3203c1 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -940,14 +940,6 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint
 
 	contentType := InstanceContentType(inst)
 
-	revert := true
-	defer func() {
-		if !revert {
-			return
-		}
-		b.DeleteInstance(inst, op)
-	}()
-
 	// Get the root disk device config.
 	rootDiskConf, err := b.instanceRootVolumeConfig(inst)
 	if err != nil {
@@ -959,6 +951,10 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint
 
 	vol := b.newVolume(volType, contentType, volStorageName, rootDiskConf)
 
+	revert := revert.New()
+	defer revert.Fail()
+	revert.Add(func() { b.DeleteInstance(inst, op) })
+
 	// If the driver doesn't support optimized image volumes then create a new empty volume and
 	// populate it with the contents of the image archive.
 	if !b.driver.Info().OptimizedImages {
@@ -998,7 +994,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint
 		return err
 	}
 
-	revert = false
+	revert.Success()
 	return nil
 }
 

From a641fd66daee754f5df2729acf3bf8d4bce0fd26 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 22 Apr 2020 11:54:12 +0100
Subject: [PATCH 2/5] lxd/storage/drivers/errors: Adds ErrCannotBeShrunk error

Used to indicate to the backend that the volume cannot be shrunk.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/errors.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lxd/storage/drivers/errors.go b/lxd/storage/drivers/errors.go
index cae5eba16a..838452192e 100644
--- a/lxd/storage/drivers/errors.go
+++ b/lxd/storage/drivers/errors.go
@@ -13,6 +13,9 @@ var ErrUnknownDriver = fmt.Errorf("Unknown driver")
 // ErrNotSupported is the "Not supported" error
 var ErrNotSupported = fmt.Errorf("Not supported")
 
+// ErrCannotBeShrunk is the "Cannot be shrunk" error
+var ErrCannotBeShrunk = fmt.Errorf("Cannot be shrunk")
+
 // ErrDeleteSnapshots is a special error used to tell the backend to delete more recent snapshots
 type ErrDeleteSnapshots struct {
 	Snapshots []string

From 72cb844fa4f9ce78e0c248ab7f6a2af65d00e9b0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 22 Apr 2020 11:54:47 +0100
Subject: [PATCH 3/5] lxd/storage/drivers/utils: Updates to shrinkFileSystem
 ErrCannotBeShrunk error

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/utils.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index edfa9c2130..9f1e55c275 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -462,7 +462,7 @@ func shrinkFileSystem(fsType string, devPath string, vol Volume, byteSize int64)
 	case "": // if not specified, default to ext4.
 		fallthrough
 	case "xfs":
-		return fmt.Errorf(`Shrinking not supported for filesystem type "%s". A dump, mkfs, and restore are required`, fsType)
+		return errors.Wrapf(ErrCannotBeShrunk, `Shrinking not supported for filesystem type "%s". A dump, mkfs, and restore are required`, fsType)
 	case "ext4":
 		return vol.UnmountTask(func(op *operations.Operation) error {
 			output, err := shared.RunCommand("e2fsck", "-f", "-y", devPath)
@@ -488,7 +488,7 @@ func shrinkFileSystem(fsType string, devPath string, vol Volume, byteSize int64)
 			return nil
 		}, nil)
 	default:
-		return fmt.Errorf(`Shrinking not supported for filesystem type "%s"`, fsType)
+		return errors.Wrapf(ErrCannotBeShrunk, `Shrinking not supported for filesystem type "%s"`, fsType)
 	}
 }
 

From 3a56e7534eb43c7b3aeabedf226895c4fc8ea51d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 22 Apr 2020 11:55:18 +0100
Subject: [PATCH 4/5] lxd/storage/backend/lxd: Updates CreateInstanceFromImage
 to detect ErrCannotBeShrunk

When creating a volume from cached image volume, if the driver returns ErrCannotBeShrunk regenerate the cached image volume so that it takes the pool's current settings (including volume.size) to allow the potential for the create to succeed a 2nd time.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_lxd.go | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 497e3203c1..8718bb7733 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -971,7 +971,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint
 		// If the driver does support optimized images then ensure the optimized image
 		// volume has been created for the archive's fingerprint and then proceed to create
 		// a new volume by copying the optimized image volume.
-		err := b.EnsureImage(fingerprint, op)
+		err = b.EnsureImage(fingerprint, op)
 		if err != nil {
 			return err
 		}
@@ -979,8 +979,30 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint
 		// No config for an image volume so set to nil.
 		imgVol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
 		err = b.driver.CreateVolumeFromCopy(vol, imgVol, false, op)
-		if err != nil {
+
+		// If the driver returns ErrCannotBeShrunk, this means that the cached volume is larger than the
+		// requested new volume size and the cached image volume, once snapshotted, cannot be shrunk.
+		// We then need to delete the cached image volume and re-create, as this should solve the issue
+		// by creating a new cached image volume using the pool's current settings (including volume.size).
+		if errors.Cause(err) == drivers.ErrCannotBeShrunk {
+			logger.Debug("Cached image volume is larger than new volume and cannot be shrunk, regenerating image volume")
+			err = b.DeleteImage(fingerprint, op)
+			if err != nil {
+				return err
+			}
+
+			err = b.EnsureImage(fingerprint, op)
+			if err != nil {
+				return err
+			}
+
+			err = b.driver.CreateVolumeFromCopy(vol, imgVol, false, op)
+			if err != nil {
+				return err
+			}
+		} else if err != nil {
 			return err
+
 		}
 	}
 

From bf686baf3ff07bc23d2f345a2005851863d13635 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 22 Apr 2020 12:14:18 +0100
Subject: [PATCH 5/5] lxd/storage/drivers: Returns ErrCannotBeShrunk when block
 volume cannot be shrunk

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_ceph_volumes.go | 2 +-
 lxd/storage/drivers/driver_lvm_volumes.go  | 2 +-
 lxd/storage/drivers/driver_zfs_volumes.go  | 2 +-
 lxd/storage/drivers/generic_vfs.go         | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lxd/storage/drivers/driver_ceph_volumes.go b/lxd/storage/drivers/driver_ceph_volumes.go
index 9c799793bf..7af0b8a4ff 100644
--- a/lxd/storage/drivers/driver_ceph_volumes.go
+++ b/lxd/storage/drivers/driver_ceph_volumes.go
@@ -815,7 +815,7 @@ func (d *ceph) SetVolumeQuota(vol Volume, size string, op *operations.Operation)
 		}
 	} else {
 		if newSizeBytes < oldSizeBytes {
-			return fmt.Errorf("You cannot shrink block volumes")
+			return errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes")
 		}
 
 		// Grow the block device.
diff --git a/lxd/storage/drivers/driver_lvm_volumes.go b/lxd/storage/drivers/driver_lvm_volumes.go
index 0c2257fa72..363a6672ae 100644
--- a/lxd/storage/drivers/driver_lvm_volumes.go
+++ b/lxd/storage/drivers/driver_lvm_volumes.go
@@ -382,7 +382,7 @@ func (d *lvm) SetVolumeQuota(vol Volume, size string, op *operations.Operation)
 		}
 	} else {
 		if newSizeBytes < oldSizeBytes {
-			return fmt.Errorf("You cannot shrink block volumes")
+			return errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes")
 		}
 
 		err = d.resizeLogicalVolume(volDevPath, newSizeBytes)
diff --git a/lxd/storage/drivers/driver_zfs_volumes.go b/lxd/storage/drivers/driver_zfs_volumes.go
index c2b7ed1996..d5e48e96b2 100644
--- a/lxd/storage/drivers/driver_zfs_volumes.go
+++ b/lxd/storage/drivers/driver_zfs_volumes.go
@@ -853,7 +853,7 @@ func (d *zfs) SetVolumeQuota(vol Volume, size string, op *operations.Operation)
 		}
 
 		if sizeBytes < oldVolSizeBytes {
-			return fmt.Errorf("You cannot shrink block volumes")
+			return errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes")
 		}
 
 		err = d.setDatasetProperties(d.dataset(vol, false), fmt.Sprintf("volsize=%d", sizeBytes))
diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go
index 88d81e8720..75f344c484 100644
--- a/lxd/storage/drivers/generic_vfs.go
+++ b/lxd/storage/drivers/generic_vfs.go
@@ -781,7 +781,7 @@ func genericVFSResizeBlockFile(filePath, size string) (bool, error) {
 	}
 
 	if newSizeBytes < oldSizeBytes {
-		return false, fmt.Errorf("You cannot shrink block volumes")
+		return false, errors.Wrap(ErrCannotBeShrunk, "You cannot shrink block volumes")
 	}
 
 	if newSizeBytes == oldSizeBytes {


More information about the lxc-devel mailing list