[PATCH 1/3] Handle nested btrfs subvolumes correctly. (#1016959)

David Lehman dlehman at redhat.com
Fri Nov 15 14:32:00 UTC 2013


Subvolumes are nested. That is to say that removing subvolume foo
will also remove subvolumes foo/bar and foo/bar/baz.
---
 blivet/devicelibs/btrfs.py |  9 ++++++---
 blivet/devices.py          | 14 ++++++++++++--
 blivet/devicetree.py       | 17 ++++++++++++++++-
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/blivet/devicelibs/btrfs.py b/blivet/devicelibs/btrfs.py
index 2f0cee4..eba27f7 100644
--- a/blivet/devicelibs/btrfs.py
+++ b/blivet/devicelibs/btrfs.py
@@ -98,15 +98,18 @@ def create_snapshot(source, dest):
 def scan_device(path):
     return btrfs(["device", "scan", path])
 
+_subvol_list_regex = r'ID (\d+) gen \d+ parent (\d+) top level \d+ path (.+)\n'
+
 # get a list of subvolumes from a mounted btrfs filesystem
 def list_subvolumes(mountpoint):
     if not os.path.ismount(mountpoint):
         raise ValueError("volume not mounted")
 
-    args = ["subvol", "list", mountpoint]
+    args = ["subvol", "list", "-p", mountpoint]
     buf = btrfs(args, capture=True)
     vols = []
-    for group in re.findall(r'ID (\d+) gen \d+ top level \d+ path (.+)\n', buf):
-        vols.append({"id": int(group[0]), "path": group[1]})
+    for group in re.findall(_subvol_list_regex, buf):
+        vols.append({"id": int(group[0]), "parent": int(group[1]),
+                     "path": group[2]})
 
     return vols
diff --git a/blivet/devices.py b/blivet/devices.py
index 8426339..725a917 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -4351,6 +4351,7 @@ class BTRFSDevice(StorageDevice):
 
 class BTRFSVolumeDevice(BTRFSDevice):
     _type = "btrfs volume"
+    vol_id = 5
 
     def __init__(self, *args, **kwargs):
         self.dataLevel = kwargs.pop("dataLevel", None)
@@ -4378,7 +4379,7 @@ class BTRFSVolumeDevice(BTRFSDevice):
                                     label=label,
                                     volUUID=self.uuid,
                                     device=self.path,
-                                    mountopts="subvolid=0")
+                                    mountopts="subvolid=" + self.vol_id)
             self.originalFormat = copy.copy(self.format)
 
     def _setFormat(self, format):
@@ -4534,7 +4535,16 @@ class BTRFSSubVolumeDevice(BTRFSDevice):
 
     @property
     def volume(self):
-        return self.parents[0]
+        parent = self.parents[0]
+        vol = None
+        while True:
+            if not isinstance(parent, BTRFSSubVolumeDevice):
+                vol = parent
+                break
+
+            parent = parent.parents[0]
+
+        return vol
 
     def setupParents(self, orig=False):
         """ Run setup method of all parent devices. """
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index 2cde0ff..0311e42 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -1590,14 +1590,29 @@ class DeviceTree(object):
             for subvol_dict in btrfs_dev.listSubVolumes():
                 vol_id = subvol_dict["id"]
                 vol_path = subvol_dict["path"]
+                parent_id = subvol_dict["parent"]
                 if vol_path in [sv.name for sv in btrfs_dev.subvolumes]:
                     continue
+
+                # look up the parent subvol
+                parent = None
+                subvols = [btrfs_dev] + btrfs_dev.subvolumes
+                for sv in subvols:
+                    if sv.vol_id == parent_id:
+                        parent = sv
+                        break
+
+                if parent is None:
+                    log.error("failed to find parent (%d) for subvol %s"
+                              % (parent_id, vol_path))
+                    raise DeviceTreeError("could not find parent for subvol")
+
                 fmt = getFormat("btrfs", device=btrfs_dev.path, exists=True,
                                 mountopts="subvol=%s" % vol_path)
                 subvol = BTRFSSubVolumeDevice(vol_path,
                                               vol_id=vol_id,
                                               format=fmt,
-                                              parents=[btrfs_dev],
+                                              parents=[parent],
                                               exists=True)
                 self._addDevice(subvol)
 
-- 
1.8.1.4



More information about the anaconda-patches mailing list