From e0ee70d06bf0f47572f8920b6fe9a3be660dcc33 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Wed, 7 Aug 2013 13:14:51 -0500
Subject: [PATCH 2/7] Add support for preexisting lvm using raid segment types.
 (#873281)

---
 iw/lvm_dialog_gui.py      | 18 ++++++----
 iw/partition_gui.py       |  3 +-
 storage/devicelibs/lvm.py | 30 +++++++++--------
 storage/devices.py        | 22 ++++++++-----
 storage/devicetree.py     | 84 +++++++++++++++++++++++------------------------
 storage/udev.py           |  8 +++++
 6 files changed, 92 insertions(+), 73 deletions(-)

diff --git a/iw/lvm_dialog_gui.py b/iw/lvm_dialog_gui.py
index cd1e11b..629c829 100644
--- a/iw/lvm_dialog_gui.py
+++ b/iw/lvm_dialog_gui.py
@@ -50,10 +50,11 @@ class VolumeGroupEditor:
         for lv in self.lvs.values():
             _l = LVMLogicalVolumeDevice(lv['name'], vg, format=lv['format'],
                                    size=lv['size'], exists=lv['exists'],
-                                   stripes=lv['stripes'],
+                                   copies=lv['copies'],
                                    logSize=lv['logSize'],
                                    snapshotSpace=lv['snapshotSpace'])
             _l.originalFormat = lv['originalFormat']
+            _l.metaDataSize = lv['metaDataSize']
 
         return vg
 
@@ -117,8 +118,8 @@ class VolumeGroupEditor:
         resize = False
         for lv in self.lvs.values():
             # total space required by an lv may be greater than lv size.
-            vg_space = lv['size'] * lv['stripes'] + lv['logSize'] \
-                        + lv['snapshotSpace']
+            vg_space = lv['size'] * lv['copies'] + lv['logSize'] \
+                        + lv['snapshotSpace'] + lv['metaDataSize']
             clamped_vg_space = lvm.clampSize(vg_space, newpe, roundup=1)
             used += clamped_vg_space
             if lv['size'] != lvm.clampSize(lv['size'], newpe, roundup=1):
@@ -464,7 +465,7 @@ class VolumeGroupEditor:
             lvsizeentry.set_text("%Ld" % lv['size'])
 
             # Maximum size label
-            max_grow = tempvg.freeSpace / lv['stripes']
+            max_grow = tempvg.freeSpace / lv['copies']
             maxsizelabel = createAlignedLabel(_("(Max size is %s MB)") %
                                               min(lvm.getMaxLVSize(),
                                                   lv['size'] + max_grow))
@@ -812,8 +813,9 @@ class VolumeGroupEditor:
                                    'size': templv.size,
                                    'format': templv.format,
                                    'originalFormat': templv.originalFormat,
-                                   'stripes': templv.stripes,
+                                   'copies': templv.copies,
                                    'logSize': templv.logSize,
+                                   'metaDataSize': templv.metaDataSize,
                                    'snapshotSpace': templv.snapshotSpace,
                                    'exists': templv.exists}
         if self.lvs.has_key(origname) and origname != templv.lvname:
@@ -864,8 +866,9 @@ class VolumeGroupEditor:
                           'size': free,
                           'format': format,
                           'originalFormat': format,
-                          'stripes': 1,
+                          'copies': 1,
                           'logSize': 0,
+                          'metaDataSize': 0,
                           'snapshotSpace': 0,
                           'exists': False}
         self.editLogicalVolume(self.lvs[name], isNew = 1)
@@ -1303,8 +1306,9 @@ class VolumeGroupEditor:
                                    "size": lv.size,
                                    "format": copy.copy(lv.format),
                                    "originalFormat": lv.originalFormat,
-                                   "stripes": lv.stripes,
+                                   "copies": lv.copies,
                                    "logSize": lv.logSize,
+                                   "metaDataSize": lv.metaDataSize,
                                    "snapshotSpace": lv.snapshotSpace,
                                    "exists": lv.exists}
 
diff --git a/iw/partition_gui.py b/iw/partition_gui.py
index 2622dcd..3751c5e 100644
--- a/iw/partition_gui.py
+++ b/iw/partition_gui.py
@@ -1804,8 +1804,9 @@ class PartitionWindow(InstallWindow):
                               'size': vg.freeSpace,
                               'format': format,
                               'originalFormat': format,
-                              'stripes': 1,
+                              'copies': 1,
                               'logSize': 0,
+                              'metaDataSize': 0,
                               'snapshotSpace': 0,
                               'exists': False}
             lv = vgeditor.lvs[name]
diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py
index 2b34da3..c4ad88d 100644
--- a/storage/devicelibs/lvm.py
+++ b/storage/devicelibs/lvm.py
@@ -328,9 +328,10 @@ def vginfo(vg_name):
     return d
 
 def lvs(vg_name):
-    args = ["lvs", "--noheadings", "--nosuffix"] + \
-            ["--units", "m"] + \
-            ["-o", "lv_name,lv_uuid,lv_size,lv_attr"] + \
+    args = ["lvs",
+            "-a", "--unit", "k", "--nosuffix", "--nameprefixes", "--rows",
+            "--unquoted", "--noheadings",
+            "-olv_name,lv_uuid,lv_size,lv_attr,segtype"] + \
             config_args + \
             [vg_name]
 
@@ -338,20 +339,21 @@ def lvs(vg_name):
                                 args,
                                 stderr="/dev/tty5")
 
-    lvs = {}
-    for line in buf.splitlines():
-        line = line.strip()
-        if not line:
+    _vars = buf.split()
+    info = {}
+    for var in _vars:
+        (name, equals, value) = var.partition("=")
+        if not equals:
             continue
-        (name, uuid, size, attr) = line.split()
-        lvs[name] = {"size": size,
-                     "uuid": uuid,
-                     "attr": attr}
 
-    if not lvs:
-        raise LVMError(_("lvs failed for %s" % vg_name))
+        val = value.strip()
+
+        if name not in info:
+            info[name] = []
 
-    return lvs
+        info[name].append(val)
+
+    return info
 
 def lvorigin(vg_name, lv_name):
     args = ["lvs", "--noheadings", "-o", "origin"] + \
diff --git a/storage/devices.py b/storage/devices.py
index 02d73ee..1c99ac8 100644
--- a/storage/devices.py
+++ b/storage/devices.py
@@ -1870,6 +1870,7 @@ class LVMVolumeGroupDevice(DMDevice):
         self.lv_uuids = []
         self.lv_sizes = []
         self.lv_attr = []
+        self.lv_types = []
         self.hasDuplicate = False
         self.reserved_percent = 0
         self.reserved_space = 0
@@ -2301,7 +2302,7 @@ class LVMLogicalVolumeDevice(DMDevice):
     _packages = ["lvm2"]
 
     def __init__(self, name, vgdev, size=None, uuid=None,
-                 stripes=1, logSize=0, snapshotSpace=0,
+                 copies=1, logSize=0, snapshotSpace=0, segType=None,
                  format=None, exists=None, sysfsPath='',
                  grow=None, maxsize=None, percent=None,
                  singlePV=False):
@@ -2316,13 +2317,14 @@ class LVMLogicalVolumeDevice(DMDevice):
 
                 size -- the device's size (in MB)
                 uuid -- the device's UUID
-                stripes -- number of copies in the vg (>1 for mirrored lvs)
+                copies -- number of copies in the vg (>1 for mirrored lvs)
                 logSize -- size of log volume (for mirrored lvs)
                 snapshotSpace -- sum of sizes of snapshots of this lv
                 sysfsPath -- sysfs device path
                 format -- a DeviceFormat instance
                 exists -- indicates whether this is an existing device
                 singlePV -- if true, maps this lv to a single pv
+                segType -- segment type (eg: "linear", "raid1")
 
                 For new (non-existent) LVs only:
 
@@ -2353,9 +2355,11 @@ class LVMLogicalVolumeDevice(DMDevice):
 
         self.uuid = uuid
         self.snapshotSpace = snapshotSpace
-        self.stripes = stripes
+        self.copies = copies
         self.logSize = logSize
+        self.metaDataSize = 0
         self.singlePV = singlePV
+        self.segType = segType or "linear"
 
         self.req_grow = None
         self.req_max_size = 0
@@ -2382,11 +2386,11 @@ class LVMLogicalVolumeDevice(DMDevice):
     def __str__(self):
         s = DMDevice.__str__(self)
         s += ("  VG device = %(vgdev)r  percent = %(percent)s\n"
-              "  mirrored = %(mirrored)s stripes = %(stripes)d"
+              "  segment type = %(type)s copies = %(copies)d"
               "  snapshot total =  %(snapshots)dMB\n"
               "  VG space used = %(vgspace)dMB" %
               {"vgdev": self.vg, "percent": self.req_percent,
-               "mirrored": self.mirrored, "stripes": self.stripes,
+               "type": self.segType, "copies": self.copies,
                "snapshots": self.snapshotSpace, "vgspace": self.vgSpaceUsed })
         return s
 
@@ -2394,7 +2398,7 @@ class LVMLogicalVolumeDevice(DMDevice):
     def dict(self):
         d = super(LVMLogicalVolumeDevice, self).dict
         if self.exists:
-            d.update({"mirrored": self.mirrored, "stripes": self.stripes,
+            d.update({"copies": self.copies,
                       "snapshots": self.snapshotSpace,
                       "vgspace": self.vgSpaceUsed})
         else:
@@ -2430,7 +2434,7 @@ class LVMLogicalVolumeDevice(DMDevice):
 
     @property
     def mirrored(self):
-        return self.stripes > 1
+        return self.copies > 1
 
     def _setSize(self, size):
         size = self.vg.align(numeric_type(size))
@@ -2447,8 +2451,8 @@ class LVMLogicalVolumeDevice(DMDevice):
     @property
     def vgSpaceUsed(self):
         """ Space occupied by this LV, not including snapshots. """
-        return (self.vg.align(self.size, roundup=True) * self.stripes
-                + self.logSize)
+        return (self.vg.align(self.size, roundup=True) * self.copies
+                + self.logSize + self.metaDataSize)
 
     @property
     def vg(self):
diff --git a/storage/devicetree.py b/storage/devicetree.py
index ba85aab..310f955 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -1516,15 +1516,22 @@ class DeviceTree(object):
     def handleVgLvs(self, vg_device):
         ret = False
         vg_name = vg_device.name
-        lv_names = vg_device.lv_names
-        lv_uuids = vg_device.lv_uuids
-        lv_sizes = vg_device.lv_sizes
-        lv_attr = vg_device.lv_attr
 
         if not vg_device.complete:
             log.warning("Skipping LVs for incomplete VG %s" % vg_name)
             return False
 
+        lv_info = devicelibs.lvm.lvs(vg_name)
+        try:
+            lv_names = udev_device_get_lv_names(lv_info)
+            lv_uuids = udev_device_get_lv_uuids(lv_info)
+            lv_sizes = udev_device_get_lv_sizes(lv_info)
+            lv_attr = udev_device_get_lv_attr(lv_info)
+            lv_types = udev_device_get_lv_types(lv_info)
+        except KeyError as e:
+            log.warning("invalid data for VG %s: %s" % (vg_name, e))
+            return
+
         if not lv_names:
             log.debug("no LVs listed for VG %s" % vg_name)
             return False
@@ -1548,9 +1555,12 @@ class DeviceTree(object):
         # the end
         indices = range(len(lv_names))
         indices.sort(key=lambda i: lv_attr[i], cmp=lv_attr_cmp)
-        mirrors = {}
+        raid = {}
         for index in indices:
             lv_name = lv_names[index]
+            if not lv_name:
+                continue
+
             name = "%s-%s" % (vg_name, lv_name)
             if lv_attr[index][0] in 'Ss':
                 log.debug("found lvm snapshot volume '%s'" % name)
@@ -1581,29 +1591,39 @@ class DeviceTree(object):
                 continue
             elif lv_attr[index][0] in 'Ii':
                 # mirror image
-                lv_name = re.sub(r'_mimage.+', '', lv_name[1:-1])
+                lv_name = re.sub(r'_[rm]image.+', '', lv_name[1:-1])
                 name = "%s-%s" % (vg_name, lv_name)
-                if name not in mirrors:
-                    mirrors[name] = {"stripes": 0, "log": 0}
+                if name not in raid:
+                    raid[name] = {"copies": 0, "log": 0, "meta": 0}
 
-                mirrors[name]["stripes"] += 1
+                raid[name]["copies"] += 1
+                continue
+            elif lv_attr[index][0] == 'e':
+                # raid metadata volume
+                lv_name = re.sub(r'_rmeta.+', '', lv_name[1:-1])
+                name = "%s-%s" % (vg_name, lv_name)
+                raid[name]["meta"] += lv_sizes[index]
+                continue
             elif lv_attr[index][0] == 'l':
                 # log volume
                 lv_name = re.sub(r'_mlog.*', '', lv_name[1:-1])
                 name = "%s-%s" % (vg_name, lv_name)
-                if name not in mirrors:
-                    mirrors[name] = {"stripes": 0, "log": 0}
+                if name not in raid:
+                    raid[name] = {"copies": 0, "log": 0, "meta": 0}
 
-                mirrors[name]["log"] = lv_sizes[index]
+                raid[name]["log"] = lv_sizes[index]
+                continue
 
-            lv_dev = self.getDeviceByName(name)
-            if lv_dev is None:
+            lv_device = self.getDeviceByName(name)
+            if lv_device is None:
                 lv_uuid = lv_uuids[index]
                 lv_size = lv_sizes[index]
+                lv_type = lv_types[index]
                 lv_device = LVMLogicalVolumeDevice(lv_name,
                                                    vg_device,
                                                    uuid=lv_uuid,
                                                    size=lv_size,
+                                                   segType=lv_type,
                                                    exists=True)
                 self._addDevice(lv_device)
 
@@ -1614,13 +1634,15 @@ class DeviceTree(object):
                     log.info("setup of %s failed: %s"
                                         % (lv_device.name, msg))
 
-        for name, mirror in mirrors.items():
+        for name, data in raid.items():
             lv_dev = self.getDeviceByName(name)
-            lv_dev.stripes = mirror["stripes"]
-            lv_dev.logSize = mirror["log"]
-            log.debug("set %s stripes to %d, log size to %dMB, total size %dMB"
-                        % (lv_dev.name, lv_dev.stripes, lv_dev.logSize,
-                           lv_dev.vgSpaceUsed))
+            lv_dev.copies = data["copies"]
+            lv_dev.metaDataSize = data["meta"]
+            lv_dev.logSize = data["log"]
+            log.debug("set %s copies to %d, metadata size to %dMB, log size "
+                      "to %dMB, total size %dMB"
+                        % (lv_dev.name, lv_dev.copies, lv_dev.metaDataSize,
+                           lv_dev.logSize, lv_dev.vgSpaceUsed))
 
         return ret
 
@@ -1661,28 +1683,6 @@ class DeviceTree(object):
                                              exists=True)
             self._addDevice(vg_device)
 
-        # Now we add any lv info found in this pv to the vg_device, we
-        # do this for all pvs as pvs only contain lv info for lvs which they
-        # contain themselves
-        try:
-            lv_names = udev_device_get_lv_names(info)
-            lv_uuids = udev_device_get_lv_uuids(info)
-            lv_sizes = udev_device_get_lv_sizes(info)
-            lv_attr = udev_device_get_lv_attr(info)
-        except KeyError as e:
-            log.warning("invalid data for %s: %s" % (device.name, e))
-            return
-
-        for i in range(len(lv_names)):
-            # Skip empty and already added lvs
-            if not lv_names[i] or lv_names[i] in vg_device.lv_names:
-                continue
-
-            vg_device.lv_names.append(lv_names[i])
-            vg_device.lv_uuids.append(lv_uuids[i])
-            vg_device.lv_sizes.append(lv_sizes[i])
-            vg_device.lv_attr.append(lv_attr[i])
-
     def handleUdevMDMemberFormat(self, info, device):
         log_method_call(self, name=device.name, type=device.format.type)
         # either look up or create the array device
diff --git a/storage/udev.py b/storage/udev.py
index b7983af..e6455c8 100644
--- a/storage/udev.py
+++ b/storage/udev.py
@@ -399,6 +399,14 @@ def udev_device_get_lv_attr(info):
         attr = [attr]
     return attr
 
+def udev_device_get_lv_types(info):
+    segtypes = info['LVM2_SEGTYPE']
+    if not segtypes:
+        segtypes = []
+    elif not isinstance(segtypes, list):
+        segtypes = [segtypes]
+    return segtypes
+
 def udev_device_dm_subsystem_match(info, subsystem):
     """ Return True if the device matches a given device-mapper subsystem. """
     uuid = info.get("DM_UUID", "")
-- 
1.8.1.4

