From 785525da9f92b987ca35f1c75fecefc270fd724f Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Wed, 24 Jun 2015 08:48:21 -0500
Subject: [PATCH 2/3] Improve format handling for lvm snapshots.

Non-existent lvm snapshots have a copy of the origin's format as their
format. When an origin's format changes, all non-existent snapshots of
that origin must have their formats updated as well.

(cherry picked from commit 4c5e150ad0ce76e05293b0f55dfb95de7f54ced6)

Related: rhbz#1113207
---
 blivet/devices/lvm.py | 50 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 38 insertions(+), 12 deletions(-)

diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 61e8e26..1aa66dd 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -21,6 +21,7 @@
 
 from decimal import Decimal
 import abc
+import copy
 import pprint
 import re
 
@@ -31,7 +32,6 @@ from ..devicelibs import dm
 from .. import errors
 from ..flags import flags
 from .. import util
-from ..formats import getFormat
 from ..storage_log import log_method_call
 from .. import udev
 from ..size import Size
@@ -505,6 +505,10 @@ class LVMLogicalVolumeDevice(DMDevice):
                     raise ValueError("constructor requires a LVMVolumeGroupDevice instance")
             elif not isinstance(parents, LVMVolumeGroupDevice):
                 raise ValueError("constructor requires a LVMVolumeGroupDevice instance")
+
+        # When this device's format is set in the superclass constructor it will
+        # try to access self.snapshots.
+        self.snapshots = []
         DMDevice.__init__(self, name, size=size, fmt=fmt,
                           sysfsPath=sysfsPath, parents=parents,
                           exists=exists)
@@ -514,7 +518,6 @@ class LVMLogicalVolumeDevice(DMDevice):
         self.logSize = logSize
         self.metaDataSize = 0
         self.segType = segType or "linear"
-        self.snapshots = []
 
         self.req_grow = None
         self.req_max_size = Size(0)
@@ -585,6 +588,11 @@ class LVMLogicalVolumeDevice(DMDevice):
         return (self.vg.align(self.size, roundup=True) * self.copies
                 + self.logSize + self.metaDataSize)
 
+    def _setFormat(self, fmt):
+        super(LVMLogicalVolumeDevice, self)._setFormat(fmt)
+        for snapshot in (s for s in self.snapshots if not s.exists):
+            snapshot._updateFormatFromOrigin()
+
     @property
     def vg(self):
         """ This Logical Volume's Volume Group. """
@@ -815,8 +823,8 @@ class LVMSnapShotBase(object):
         Normal/old snapshots must be removed with their origin, while thin
         snapshots can remain after their origin is removed.
 
-        It is also impossible to set the format for a snapshot explicitly as it
-        always has the same format as its origin.
+        It is also impossible to set the format for a non-existent snapshot
+        explicitly as it always has the same format as its origin.
     """
     __metaclass__ = abc.ABCMeta
     _type = "lvmsnapshotbase"
@@ -860,15 +868,33 @@ class LVMSnapShotBase(object):
         if vorigin and not exists:
             raise ValueError("only existing vorigin snapshots are supported")
 
-    def _setFormat(self, fmt):
-        pass
+    def _updateFormatFromOrigin(self):
+        """ Update the snapshot's format to reflect the origin's.
+
+            .. note::
+                This should only be called for non-existent snapshot devices.
+                Once a snapshot exists its format is distinct from that of its
+                origin.
+
+        """
+        fmt = copy.deepcopy(self.origin.format)
+        fmt.exists = False
+        if hasattr(fmt, "mountpoint"):
+            fmt.mountpoint = ""
+            fmt._chrootedMountpoint = None
+            fmt.device = self.path # pylint: disable=no-member
+
+        super(LVMSnapShotBase, self)._setFormat(fmt)
 
-    def _getFormat(self):
-        if self.origin is None:
-            fmt = getFormat(None)
+    def _setFormat(self, fmt):
+        # If a snapshot exists it can have a format that is distinct from its
+        # origin's. If it does not exist its format must be a copy of its
+        # origin's.
+        if self.exists: # pylint: disable=no-member
+            super(LVMSnapShotBase, self)._setFormat(fmt)
         else:
-            fmt = self.origin.format
-        return fmt
+            log.info("copying %s origin's format", self.name) # pylint: disable=no-member
+            self._updateFormatFromOrigin()
 
     @abc.abstractmethod
     def _create(self):
@@ -1213,7 +1239,7 @@ class LVMThinSnapShotDevice(LVMSnapShotBase, LVMThinLogicalVolumeDevice):
 
         LVMSnapShotBase.__init__(self, origin=origin, exists=exists)
         LVMThinLogicalVolumeDevice.__init__(self, name, parents=parents,
-                                            sysfsPath=sysfsPath,fmt=None,
+                                            sysfsPath=sysfsPath,fmt=fmt,
                                             segType=segType,
                                             uuid=uuid, size=size, exists=exists)
 
-- 
2.4.3

