[PATCH 1/5][blivet] Handle nested btrfs subvolumes correctly. (#1016959)
David Lehman
dlehman at redhat.com
Fri Nov 22 16:00:07 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 | 12 +++++++++---
blivet/devices.py | 14 ++++++++++++--
blivet/devicetree.py | 17 ++++++++++++++++-
3 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/blivet/devicelibs/btrfs.py b/blivet/devicelibs/btrfs.py
index 2f0cee4..bde165d 100644
--- a/blivet/devicelibs/btrfs.py
+++ b/blivet/devicelibs/btrfs.py
@@ -32,6 +32,9 @@ _ = lambda x: gettext.ldgettext("blivet", x)
import logging
log = logging.getLogger("blivet")
+# this is the volume id btrfs always assigns to the top-level volume/tree
+MAIN_VOLUME_ID = 5
+
def btrfs(args, capture=False):
if capture:
exec_func = util.capture_output
@@ -98,15 +101,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 54ece22..82f1872 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -4346,6 +4346,7 @@ class BTRFSDevice(StorageDevice):
class BTRFSVolumeDevice(BTRFSDevice):
_type = "btrfs volume"
+ vol_id = btrfs.MAIN_VOLUME_ID
def __init__(self, *args, **kwargs):
self.dataLevel = kwargs.pop("dataLevel", None)
@@ -4373,7 +4374,7 @@ class BTRFSVolumeDevice(BTRFSDevice):
label=label,
volUUID=self.uuid,
device=self.path,
- mountopts="subvolid=0")
+ mountopts="subvolid=%d" % self.vol_id)
self.originalFormat = copy.copy(self.format)
def _setFormat(self, format):
@@ -4529,7 +4530,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 bad135c..8ab1e5f 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