[PATCH 5/5][anaconda] Handle non-leaf btrfs volumes with mountpoints. (#1016959)

David Lehman dlehman at redhat.com
Fri Nov 22 16:00:11 UTC 2013


btrfs allows mounting of non-leaf devices, which is unusual.

This could be a top-level volume or a subvolume that contains other
subvolumes.

The volume could have a mountpoint in a previous installation or it
could have one assigned via kickstart, so we must be able to handle
showing them.

Since the btrfs volume is treated as a container the only
configuration allowed on one is setting a mountpoint or running the
modify container dialog.
---
 pyanaconda/ui/gui/spokes/custom.py | 46 ++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 1950a5b..f19da80 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -316,7 +316,7 @@ class ConfirmDeleteDialog(GUIObject):
         self.window.destroy()
 
     # pylint: disable-msg=W0221
-    def refresh(self, mountpoint, device, rootName):
+    def refresh(self, mountpoint, device, rootName, subvols=False):
         GUIObject.refresh(self)
         label = self.builder.get_object("confirmLabel")
 
@@ -331,7 +331,10 @@ class ConfirmDeleteDialog(GUIObject):
         else:
             txt = device
 
-        label_text = _("Are you sure you want to delete all of the data on %s?") % txt
+        if not subvols:
+            label_text = _("Are you sure you want to delete all of the data on %s?") % txt
+        else:
+            label_text = _("Are you sure you want to delete all of the data on %s, including subvolumes and/or snapshots?") % txt
 
         label.set_text(label_text)
 
@@ -796,7 +799,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
     def unusedDevices(self):
         unused_devices = [d for d in self.__storage.unusedDevices
                                 if d.disks and d.mediaPresent and
-                                not d.partitioned and d.isleaf]
+                                not d.partitioned and
+                                (d.isleaf or d.type.startswith("btrfs"))]
         # add incomplete VGs and MDs
         incomplete = [d for d in self.__storage.devicetree._devices
                             if not getattr(d, "complete", True)]
@@ -909,7 +913,9 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
     @property
     def new_devices(self):
         # A device scheduled for formatting only belongs in the new root.
-        new_devices = [d for d in self._devices if d.isleaf and
+        new_devices = [d for d in self._devices if (d.isleaf or
+                                                    d.type.startswith("btrfs"))
+                                                   and
                                                    not d.format.exists and
                                                    not d.partitioned]
 
@@ -1261,6 +1267,16 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             self._populate_right_side(selector)
             return
 
+        # If the device is a btrfs volume, the only things we can set/update
+        # are mountpoint and container-wide settings.
+        if device_type == DEVICE_TYPE_BTRFS and hasattr(use_dev, "subvolumes"):
+            size = 0
+            changed_size = False
+            encrypted = False
+            changed_encryption = False
+            raid_level = None
+            changed_raid_level = False
+
         with ui_storage_logger():
             # create a new factory using the appropriate size and type
             factory = devicefactory.get_device_factory(self.__storage,
@@ -1659,11 +1675,12 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             self._device_container_raid_level = get_raid_level(use_dev.vg)
             self._device_container_encrypted = use_dev.vg.encrypted
             self._device_container_size = use_dev.vg.size_policy
-        elif hasattr(use_dev, "volume"):
-            self._device_container_name = use_dev.volume.name
-            self._device_container_raid_level = get_raid_level(use_dev.volume)
-            self._device_container_encrypted = use_dev.volume.encrypted
-            self._device_container_size = use_dev.volume.size_policy
+        elif hasattr(use_dev, "volume") or hasattr(use_dev, "subvolumes"):
+            volume = getattr(use_dev, "volume", use_dev)
+            self._device_container_name = volume.name
+            self._device_container_raid_level = get_raid_level(volume)
+            self._device_container_encrypted = volume.encrypted
+            self._device_container_size = volume.size_policy
         else:
             self._device_container_name = None
             self._device_container_raid_level = None
@@ -1870,7 +1887,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
         self._populate_raid(raid_level)
         self._populate_container(device=use_dev)
         # do this last in case this was set sensitive in on_device_type_changed
-        if use_dev.exists:
+        if use_dev.exists or use_dev.type == "btrfs volume":
             fancy_set_sensitive(self._nameEntry, False)
 
     ###
@@ -2075,6 +2092,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             try:
                 if device.isDisk:
                     self.__storage.initializeDisk(device)
+                elif device.type.startswith("btrfs") and not device.isleaf:
+                    self.__storage.recursiveRemove(device)
                 else:
                     self.__storage.destroyDevice(device)
             except StorageError as e:
@@ -2188,8 +2207,10 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             # schedule actions to delete the thing.
             dialog = ConfirmDeleteDialog(self.data)
             with enlightbox(self.window, dialog.window):
+                subvols = (device.type.startswith("btrfs") and
+                           not device.isleaf)
                 dialog.refresh(getattr(device.format, "mountpoint", ""),
-                               device.name, root_name)
+                               device.name, root_name, subvols=subvols)
                 rc = dialog.run()
 
                 if rc == 0:
@@ -2665,7 +2686,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             map(really_show, [self._containerLabel, self._containerCombo, self._modifyContainerButton])
 
             # make the combo and button insensitive for existing LVs
-            can_change_container = (device is not None and not device.exists)
+            can_change_container = (device is not None and not device.exists and
+                                    device != container)
             fancy_set_sensitive(self._containerCombo, can_change_container)
             container_exists = getattr(container, "exists", False)
             self._modifyContainerButton.set_sensitive(not container_exists)
-- 
1.8.1.4



More information about the anaconda-patches mailing list