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")
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