[PATCH] Handle system crappyness.

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

 



* 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 (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/partitioning.py (clearPartitions): We cannot touch the
  partitions that are ignored in autopart.
---
 storage/devicelibs/lvm.py |   37 +++++++++++++--
 storage/devices.py        |   32 ++++++++++++-
 storage/devicetree.py     |  111 +++++++++++++++++++++++++++++++++++++++++++++
 storage/formats/lvmpv.py  |    6 ++-
 storage/partitioning.py   |    4 ++
 5 files changed, 181 insertions(+), 9 deletions(-)

diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py
index 8b755a4..40a6902 100644
--- a/storage/devicelibs/lvm.py
+++ b/storage/devicelibs/lvm.py
@@ -99,6 +99,26 @@ def lvm_cc_addFilterRejectRegexp(regexp):
     _composeConfig()
 # End config_args handling code.
 
+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 +303,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 397a648..3c3c4fb 100644
--- a/storage/devices.py
+++ b/storage/devices.py
@@ -1692,9 +1692,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. """
@@ -1823,6 +1829,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 """
@@ -1922,6 +1938,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 b015b55..83015e1 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.
 
@@ -1308,12 +1338,88 @@ 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
+
+            for parent in vg.parents:
+                parent.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)
+
+            # remove VG device from list.
+            self._removeDevice(vg)
+
+        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.addIgnoredDisk(device.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:
+                # The user chose not to reinitialize.
+                # hopefully this will ignore the vg components too.
+                for lv in device.vg.lvs:
+                    self.addIgnoredDisk(lv.name)
+                    #self._removeDevice(lv)
+                #self._removeDevice(device.vg)
+                self.addIgnoredDisk(device.vg.name)
+                for parent in device.vg.parents:
+                    self.addIgnoredDisk(parent.name)
+                    #self.protectedPartitions.append(parent.name)
+            return
+
     def populate(self):
         """ Locate all storage devices. """
         # each iteration scans any devices that have appeared since the
@@ -1343,6 +1449,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()
 
diff --git a/storage/partitioning.py b/storage/partitioning.py
index 8243080..f48d1b2 100644
--- a/storage/partitioning.py
+++ b/storage/partitioning.py
@@ -290,6 +290,10 @@ def clearPartitions(storage):
                                  parted.PARTITION_LOGICAL):
             continue
 
+        # we will ignore it if its in the ignored disk
+        if part.name in storage.devicetree._ignoredDisks:
+            continue
+
         if storage.clearPartType == CLEARPART_TYPE_ALL:
             clear = True
         else:
-- 
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