[PATCH] Handle system crappyness.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* storage/__init__.py (createSuggestedVGName): Take into account the new
  lvm black list.

* storage/devicelibs/lvm.py (zeroLvmMetadata): zero out the LVM metadata
  only.  This basically means from 513 byte and on.  This will also
  ignore the firs 512 bytes if we are in a partition, but that does not
  matter because LVM does not touch those bits anyways.
* storage/devicelibs/lvm.py (blacklistVG): New function, add a VG to a
  the black list.
* storage/devicelibs/lvm.py (vgreduce): introduces a new argument to the
  function.  rm means use the lvm --removemissing option.

* storage/devices.py (LVMVolumeGroupDevice.complete): New function to
  evaluate if VG is consistent.
* storage/devices.py (LVMLogicalVolumeDevice.complete): Likewise for
  LVs.

* storage/devicetree.py (_handleInconsistencies): New function intended to
  catch all unwanted behavior from the system before continuing.
* storage/devicetree.py (questionReinitILVM): New function intended
  to ask the user what to do in case we find inconsistent LVM metadata.

* storage/formats/lvmpv.py (LVMPhysicalVolume.destroy): Use the
  zeroLvmMetaData in case pvremove fails.
---
 storage/__init__.py       |    6 ++-
 storage/devicelibs/lvm.py |   47 ++++++++++++++---
 storage/devices.py        |   32 +++++++++++-
 storage/devicetree.py     |  124 ++++++++++++++++++++++++++++++++++++++++++++-
 storage/formats/lvmpv.py  |    6 ++-
 5 files changed, 200 insertions(+), 15 deletions(-)

diff --git a/storage/__init__.py b/storage/__init__.py
index 6bb7a84..e169c47 100644
--- a/storage/__init__.py
+++ b/storage/__init__.py
@@ -632,13 +632,15 @@ class Storage(object):
         else:
             vgtemplate = "VolGroup"
 
-        if vgtemplate not in vgnames:
+        if vgtemplate not in vgnames and \
+                vgtemplate not in lvm.lvm_vg_blacklist:
             return vgtemplate
         else:
             i = 0
             while 1:
                 tmpname = "%s%02d" % (vgtemplate, i,)
-                if not tmpname in vgnames:
+                if not tmpname in vgnames and \
+                        tmpname not in lvm.lvm_vg_blacklist:
                     break
 
                 i += 1
diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py
index 8b755a4..3226a0a 100644
--- a/storage/devicelibs/lvm.py
+++ b/storage/devicelibs/lvm.py
@@ -73,7 +73,7 @@ def _composeConfig():
 
     if len(rejects) > 0:
         for i in range(len(rejects)):
-            filter_string = filter_string + ("\"r|%s|\", " % rejects[i])
+            filter_string = filter_string + ("\"r|%s|\"," % rejects[i])
 
 
     filter_string = " filter=[%s] " % filter_string.strip(",")
@@ -86,7 +86,7 @@ def _composeConfig():
     # devices_string can have (inside the brackets) "dir", "scan",
     # "preferred_names", "filter", "cache_dir", "write_cache_state",
     # "types", "sysfs_scan", "md_component_detection".  see man lvm.conf.
-    devices_string = " devices { %s } " % (filter_string) # strings can be added
+    devices_string = " devices {%s} " % (filter_string) # strings can be added
     config_string = devices_string # more strings can be added.
     config_args = ["--config", config_string]
 
@@ -99,6 +99,32 @@ def lvm_cc_addFilterRejectRegexp(regexp):
     _composeConfig()
 # End config_args handling code.
 
+# Names that should not be used int the creation of VGs
+lvm_vg_blacklist = []
+def blacklistVG(name):
+    global lvm_vg_blacklist
+    lvm_vg_blacklist.append(name)
+
+def zeroLvmMetadata(device):
+    """ This dds from byte 513 to 200Mb+513 of the disk.
+
+    We assume that lvm has nothing to do with the first 512 bytes.
+    We assume that 200Mb is enough.  My tests failed with 100Mb for
+    some unknown reason.
+    """
+    try:
+        fd = os.open(device, os.O_WRONLY)
+        os.lseek(fd, 513, os.SEEK_SET)
+        for i in range(200):
+            os.write(fd, "\0"*1024*1024)
+        os.close(fd)
+
+    except OSError as e:
+        if e.errno == 28: # No space left in device
+            pass
+        else:
+            raise LVMError("Falied to zero LVM data on %s." % device)
+
 def getPossiblePhysicalExtents(floor=0):
     """Returns a list of integers representing the possible values for
        the physical extent of a volume group.  Value is in KB.
@@ -283,11 +309,18 @@ def vgdeactivate(vg_name):
     if rc:
         raise LVMError("vgdeactivate failed for %s" % vg_name)
 
-def vgreduce(vg_name, pv_list):
-    args = ["vgreduce"] + \
-            config_args + \
-            [vg_name] + \
-            pv_list
+def vgreduce(vg_name, pv_list, rm=False):
+    """ Reduce a VG.
+
+    rm -> with RemoveMissing option.
+    Use pv_list when rm=False, otherwise ignore pv_list and call vgreduce with
+    the --removemissing option.
+    """
+    args = ["vgreduce"]
+    if rm:
+        args.extend(["--removemissing", vg_name])
+    else:
+        args.extend([vg_name] + pv_list)
 
     rc = iutil.execWithRedirect("lvm", args,
                                 stdout = "/dev/tty5",
diff --git a/storage/devices.py b/storage/devices.py
index 0922778..1a16a0e 100644
--- a/storage/devices.py
+++ b/storage/devices.py
@@ -1632,9 +1632,15 @@ class LVMVolumeGroupDevice(DMDevice):
 
         self.teardown()
 
-        lvm.vgremove(self.name)
-        self.notifyKernel()
-        self.exists = False
+        # this sometimes fails for some reason.
+        try:
+            lvm.vgreduce(self.name, [], rm=True)
+            lvm.vgremove(self.name)
+        except lvm.LVMErorr:
+            raise DeviceError("Could not completely remove VG %s" % self.name)
+        finally:
+            self.notifyKernel()
+            self.exists = False
 
     def reduce(self, pv_list):
         """ Remove the listed PVs from the VG. """
@@ -1763,6 +1769,16 @@ class LVMVolumeGroupDevice(DMDevice):
         """ A list of this VG's LVs """
         return self._lvs[:]     # we don't want folks changing our list
 
+    @property
+    def complete(self):
+        """Check if the vg has all its pvs in the system
+        Return True if complete.
+        """
+        if len(self.pvs) == self.pvCount:
+            return True
+        else:
+            return False
+
 
 class LVMLogicalVolumeDevice(DMDevice):
     """ An LVM Logical Volume """
@@ -1862,6 +1878,16 @@ class LVMLogicalVolumeDevice(DMDevice):
         """ The LV's name (not including VG name). """
         return self._name
 
+    @property
+    def complete(self):
+        """ Test if vg exits and if it has all pvs. """
+        if not self.vg.exists:
+            return False
+
+        if not self.vg.complete:
+            return False
+        return True
+
     def setup(self, intf=None):
         """ Open, or set up, a device. """
         log_method_call(self, self.name, status=self.status)
diff --git a/storage/devicetree.py b/storage/devicetree.py
index 850a220..c6aceb7 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -136,6 +136,36 @@ def questionInitializeDisk(intf=None, name=None):
             retVal = True
     return retVal
 
+def questionReinitILVM(intf=None, pv_names=None, lv_name=None, vg_name=None):
+    retVal = False # The less destructive default
+    if not intf or not pv_names or (lv_name is None and vg_name is None):
+        pass
+    else:
+        if vg_name is not None:
+            message = "%s Volume Group" % vg_name
+        elif lv_name is not None:
+            message = "%s Logical Volume" % lv_name
+
+
+        rc = intf.messageWindow(_("Warning"),
+                  _("Error processing LVM.\n"
+                    "It seems that there is inconsistent LVM data. "
+                    "(%s) make(s) up %s. "
+                    "You can reinitialize all related PVs, which will "
+                    "erase all LVM metadata. Or ignore, which will "
+                    "preserve contents.")
+                    %(str(pv_names), message),
+                type="custom",
+                custom_buttons = [ _("_Ignore drive(s)"),
+                                   _("_Re-initialize drive(s)") ],
+                custom_icon="question")
+        if rc == 0:
+            pass
+        else:
+            retVal = True # thie means clobber.
+
+    return retVal
+
 class DeviceTree(object):
     """ A quasi-tree that represents the devices in the system.
 
@@ -647,7 +677,7 @@ class DeviceTree(object):
         log.debug("added %s (%s) to device tree" % (newdev.name,
                                                     newdev.type))
 
-    def _removeDevice(self, dev, force=None):
+    def _removeDevice(self, dev, force=None, moddisk=True):
         """ Remove a device from the tree.
 
             Only leaves may be removed.
@@ -660,7 +690,8 @@ class DeviceTree(object):
             raise ValueError("Cannot remove non-leaf device '%s'" % dev.name)
 
         # if this is a partition we need to remove it from the parted.Disk
-        if isinstance(dev, PartitionDevice) and dev.disk is not None:
+        if moddisk and isinstance(dev, PartitionDevice) and \
+                dev.disk is not None:
             # if this partition hasn't been allocated it could not have
             # a disk attribute
             dev.disk.partedDisk.removePartition(dev.partedPartition)
@@ -1318,12 +1349,96 @@ class DeviceTree(object):
                                                                size=lv_size,
                                                                exists=True)
                             self._addDevice(lv_device)
+
                             try:
                                 lv_device.setup()
                             except DeviceError as e:
                                 log.info("setup of %s failed: %s" 
                                                     % (lv_device.name, e))
 
+    def _handleInconsistencies(self, device):
+        def reinitializeVG(vg):
+            # First we remove VG data
+            try:
+                vg.destroy()
+            except DeviceError:
+                # the pvremoves will finish the job.
+                log.debug("There was an error destroying the VG %s." % vg.name)
+                pass
+
+            # remove VG device from list.
+            self._removeDevice(vg)
+
+            for parent in vg.parents:
+                parent.format.destroy()
+
+                # Give the vg the a default format
+                kwargs = {"uuid": parent.uuid,
+                          "label": parent.diskLabel,
+                          "device": parent.path,
+                          "exists": parent.exists}
+                parent.format = formats.getFormat(*[""], **kwargs)
+
+        if device.type == "lvmvg":
+            paths = []
+            for parent in device.parents:
+                paths.append(parent.path)
+
+            # when zeroMbr is true he wont ask.
+            if not device.complete and (self.zeroMbr or \
+                    questionReinitILVM(intf=self.intf, \
+                        vg_name=device.name, pv_names=paths)):
+                reinitializeVG(device)
+
+            elif not device.complete:
+                # The user chose not to reinitialize.
+                # hopefully this will ignore the vg components too.
+                self._removeDevice(vg)
+                lvm.lvm_cc_addFilterRejectRegexp(vg.name)
+                lvm.blacklistVG(vg.name)
+                for parent in vg.parents:
+                    self._removeDevice(parent, moddisk=False)
+                    lvm.lvm_cc_addFilterRejectRegexp(parent.name)
+
+            return
+
+        elif device.type == "lvmlv":
+            # we might have already fixed this.
+            if device not in self._devices or \
+                    device.name in self._ignoredDisks:
+                return
+
+            paths = []
+            for parent in device.vg.parents:
+                paths.append(parent.path)
+
+            if not device.complete and (self.zeroMbr or \
+                questionReinitILVM(intf=self.intf, \
+                    lv_name=device.name, pv_names=paths)):
+
+                # destroy all lvs.
+                for lv in device.vg.lvs:
+                    lv.destroy()
+                    device.vg._removeLogVol(lv)
+                    self._removeDevice(lv)
+
+                reinitializeVG(device.vg)
+
+            elif not device.complete:
+                # ignore all the lvs.
+                for lv in device.vg.lvs:
+                    self._removeDevice(lv)
+                    lvm.lvm_cc_addFilterRejectRegexp(lv.name)
+                # ignore the vg
+                self._removeDevice(device.vg)
+                lvm.lvm_cc_addFilterRejectRegexp(device.vg.name)
+                lvm.blacklistVG(device.vg.name)
+                # ignore all the pvs
+                for parent in device.vg.parents:
+                    self._removeDevice(parent, moddisk=False)
+                    lvm.lvm_cc_addFilterRejectRegexp(parent.name)
+            return
+
     def populate(self):
         """ Locate all storage devices. """
         # each iteration scans any devices that have appeared since the
@@ -1353,6 +1468,11 @@ class DeviceTree(object):
             for dev in devices:
                 self.addUdevDevice(dev)
 
+        # After having the complete tree we make sure that the system
+        # inconsistencies are ignored or resolved.
+        for leaf in self.leaves:
+            self._handleInconsistencies(leaf)
+
         self.teardownAll()
 
     def teardownAll(self):
diff --git a/storage/formats/lvmpv.py b/storage/formats/lvmpv.py
index cc243eb..ca11130 100644
--- a/storage/formats/lvmpv.py
+++ b/storage/formats/lvmpv.py
@@ -106,7 +106,11 @@ class LVMPhysicalVolume(DeviceFormat):
             raise PhysicalVolumeError("device is active")
 
         # FIXME: verify path exists?
-        lvm.pvremove(self.device)
+        try:
+            lvm.pvremove(self.device)
+        except LVMError:
+            lvm.zeroLvmMetadata(self.path)
+
         self.exists = False
         self.notifyKernel()
 
-- 
1.6.0.6

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux