[PATCH 13/15] Add support for btrfs to the devicetree.

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

 



Adds support for scanning existing btrfs, including subvolumes.

Also adds an optional arg to getDeviceByPath to accommodate the fact
that btrfs volumes don't have a separate device node to represent the
top-level volume.

btrfs format.uuid is the member device's UUID (ID_FS_UUID_SUB),
while format.volUUID (ID_FS_UUID) is the top-level volume's UUID.
This prevents some further madness in which multiple devices would
have the same UUID.
---
 pyanaconda/storage/devices.py      |   15 ++++---
 pyanaconda/storage/devicetree.py   |   80 ++++++++++++++++++++++++++++++------
 pyanaconda/storage/formats/fs.py   |    2 +-
 pyanaconda/storage/partitioning.py |    4 +-
 4 files changed, 79 insertions(+), 22 deletions(-)

diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py
index de78602..0e641f3 100644
--- a/pyanaconda/storage/devices.py
+++ b/pyanaconda/storage/devices.py
@@ -3941,18 +3941,21 @@ class BTRFSVolumeDevice(BTRFSDevice):
         self.subvolumes = []
 
         for parent in self.parents:
+            if parent.format.type != "btrfs":
+                raise ValueError("member device %s is not BTRFS" % parent.name)
+
             if parent.format.exists and self.exists and \
-               parent.format.uuid != self.uuid:
+               parent.format.volUUID != self.uuid:
                 raise ValueError("BTRFS member device %s UUID %s does not "
                                  "match volume UUID %s" % (parent.name,
-                                                           parent.format.uuid,
-                                                           self.uuid))
+                                 parent.format.volUUID, self.uuid))
 
         if self.parents and not self.format.type:
             label = getattr(self.parents[0].format, "label", None)
-            self.format = getFormat("btrfs", exists=self.exists,
+            self.format = getFormat("btrfs",
+                                    exists=self.exists,
                                     label=label,
-                                    uuid=self.uuid,
+                                    volUUID=self.uuid,
                                     device=self.path)
 
         label = getattr(self.format, "label", None)
@@ -3980,7 +3983,7 @@ class BTRFSVolumeDevice(BTRFSDevice):
         if device.format.type != "btrfs":
             raise ValueError("addDevice requires a btrfs device as sole arg")
 
-        if device.format.uuid != self.uuid:
+        if device.format.volUUID != self.uuid:
             raise ValueError("device UUID does not match the volume UUID")
 
         if device in self.parents:
diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py
index fb40cf6..f4ac54c 100644
--- a/pyanaconda/storage/devicetree.py
+++ b/pyanaconda/storage/devicetree.py
@@ -336,7 +336,7 @@ class DeviceTree(object):
             Raise ValueError if the device's identifier is already
             in the list.
         """
-        if newdev.path in [d.path for d in self._devices] and \
+        if newdev.uuid and newdev.uuid in [d.uuid for d in self._devices] and \
            not isinstance(newdev, NoDevice):
             raise ValueError("device is already in tree")
 
@@ -1558,6 +1558,42 @@ class DeviceTree(object):
                 #device.format.raidmem = block.getMemFromRaidSet(dm_array,
                 #        major=major, minor=minor, uuid=uuid, name=name)
 
+    def handleBTRFSFormat(self, info, device):
+        log_method_call(self, name=device.name)
+        name = udev_device_get_name(info)
+        sysfs_path = udev_device_get_sysfs_path(info)
+        uuid = udev_device_get_uuid(info)
+
+        btrfs_dev = None
+        for d in self.devices:
+            if isinstance(d, BTRFSVolumeDevice) and d.uuid == uuid:
+                btrfs_dev = d
+                break
+
+        if btrfs_dev:
+            log.info("found btrfs volume %s" % btrfs_dev.name)
+            btrfs_dev._addDevice(device)
+        else:
+            label = udev_device_get_label(info)
+            log.info("creating btrfs volume btrfs.%s" % label)
+            btrfs_dev = BTRFSVolumeDevice(label, parents=[device], uuid=uuid,
+                                          exists=True)
+            self._addDevice(btrfs_dev)
+
+        if not btrfs_dev.subvolumes:
+            for subvol_dict in btrfs_dev.listSubVolumes():
+                vol_id = subvol_dict["id"]
+                vol_path = subvol_dict["path"]
+                if vol_path in [sv.name for sv in btrfs_dev.subvolumes]:
+                    continue
+                fmt = getFormat("btrfs", device=btrfs_dev.path, exists=True,
+                                mountopts="subvol=%d" % vol_id)
+                subvol = BTRFSSubVolumeDevice(vol_path,
+                                              vol_id=vol_id,
+                                              format=fmt,
+                                              parents=[btrfs_dev])
+                self._addDevice(subvol)
+
     def handleUdevDeviceFormat(self, info, device):
         log_method_call(self, name=getattr(device, "name", None))
         name = udev_device_get_name(info)
@@ -1636,6 +1672,11 @@ class DeviceTree(object):
                 apple = formats.getFormat("appleboot")
                 if apple.minSize <= device.size <= apple.maxSize:
                     args[0] = "appleboot"
+        elif format_type == "btrfs":
+            # the format's uuid attr will contain the UUID_SUB, while the
+            # overarching volume UUID will be stored as volUUID
+            kwargs["uuid"] = info["ID_FS_UUID_SUB"]
+            kwargs["volUUID"] = uuid
 
         try:
             log.info("type detected on '%s' is '%s'" % (name, format_type,))
@@ -1665,6 +1706,8 @@ class DeviceTree(object):
             self.handleUdevLVMPVFormat(info, device)
         elif device.format.type == "multipath_member":
             self.handleMultipathMemberFormat(info, device)
+        elif device.format.type == "btrfs":
+            self.handleBTRFSFormat(info, device)
 
     def updateDeviceFormat(self, device):
         log.info("updating format of device: %s" % device)
@@ -2051,21 +2094,30 @@ class DeviceTree(object):
         log_method_return(self, found)
         return found
 
-    def getDeviceByPath(self, path):
+    def getDeviceByPath(self, path, preferLeaves=True):
         log_method_call(self, path=path)
         if not path:
             log_method_return(self, None)
             return None
 
-        found = None
+        leaf = None
+        other = None
         for device in self._devices:
-            if device.path == path:
-                found = device
-                break
-            elif (device.type == "lvmlv" or device.type == "lvmvg") and \
-                    device.path == path.replace("--","-"):
-                found = device
-                break
+            if (device.path == path or
+                ((device.type == "lvmlv" or device.type == "lvmvg") and
+                 device.path == path.replace("--","-"))):
+                if device.isleaf and not leaf:
+                    leaf = device
+                elif not other:
+                    other = device
+
+        if preferLeaves:
+            all_devs = [leaf, other]
+        else:
+            all_devs = [other, leaf]
+        all_devs = [d for d in all_devs if d]
+        if all_devs:
+            found = all_devs[0]
 
         log_method_return(self, found)
         return found
@@ -2082,9 +2134,9 @@ class DeviceTree(object):
         """ List of device instances """
         devices = []
         for device in self._devices:
-            if device.path in [d.path for d in devices] and \
+            if device.uuid and device.uuid in [d.uuid for d in devices] and \
                not isinstance(device, NoDevice):
-                raise DeviceTreeError("duplicate paths in device tree")
+                raise DeviceTreeError("duplicate uuids in device tree")
 
             devices.append(device)
 
@@ -2132,7 +2184,9 @@ class DeviceTree(object):
         """
         labels = {}
         for dev in self._devices:
-            if dev.format and getattr(dev.format, "label", None):
+            # don't include btrfs member devices
+            if getattr(dev.format, "label", None) and \
+               (dev.format.type != "btrfs" or isinstance(dev, BTRFSDevice)):
                 labels[dev.format.label] = dev
 
         return labels
diff --git a/pyanaconda/storage/formats/fs.py b/pyanaconda/storage/formats/fs.py
index 3c3229f..0942402 100644
--- a/pyanaconda/storage/formats/fs.py
+++ b/pyanaconda/storage/formats/fs.py
@@ -1140,8 +1140,8 @@ class BTRFS(FS):
     # partedSystem = fileSystemType["btrfs"]
 
     def __init__(self, *args, **kwargs):
-        self.uuidSub = kwargs.pop("uuidSub", None)
         super(BTRFS, self).__init__(*args, **kwargs)
+        self.volUUID = kwargs.pop("volUUID", None)
 
     def create(self, *args, **kwargs):
         # filesystem creation is done in storage.devicelibs.btrfs.create_volume
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py
index 4a80a8b..8669c82 100644
--- a/pyanaconda/storage/partitioning.py
+++ b/pyanaconda/storage/partitioning.py
@@ -261,8 +261,8 @@ def _scheduleVolumes(storage, devs):
 def scheduleShrinkActions(storage):
     """ Schedule actions to shrink partitions as per autopart selection. """
     for (path, size) in storage.shrinkPartitions.items():
-        device = storage.devicetree.getDeviceByPath(path)
-        if not device:
+        device = storage.devicetree.getDeviceByPath(path, preferLeaves=False)
+        if not device or not isinstance(device, PartitionDevice):
             raise StorageError("device %s scheduled for shrink disappeared"
                                 % path)
         storage.devicetree.registerAction(ActionResizeFormat(device, size))
-- 
1.7.3.4

_______________________________________________
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