Re: [PATCH] Handle system crappyness.

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

 



Note that this patch already contains the "don't create a vg with an
existing conflicting name" functionality.

On Tue, Mar 17, 2009 at 02:56:51PM +0100, Joel Granados Moreno wrote:
> * 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

-- 
Joel Andres Granados
Brno, Czech Republic, Red Hat.

_______________________________________________
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