From 0a39a937e2d69faf71e41f948c6aa0af1cf6294e Mon Sep 17 00:00:00 2001 From: Davide Cavalca Date: Jul 10 2020 16:15:05 +0000 Subject: add basic support for btrfs subvolumes --- diff --git a/appcreate/appliance.py b/appcreate/appliance.py index 38a2a40..f5d7ec1 100644 --- a/appcreate/appliance.py +++ b/appcreate/appliance.py @@ -122,6 +122,7 @@ class ApplianceImageCreator(ImageCreator): #list of partitions from kickstart file parts = kickstart.get_partitions(self.ks) + # need to eliminate duplicate partitions # this is a bit of a hack but we assume the last partition for a given mount point is the one we want mountpoints = [] @@ -225,11 +226,21 @@ class ApplianceImageCreator(ImageCreator): else: self.__instloop.add_partition(int(p.size), "sda", p.mountpoint, p.fstype) + # FIXME: this only works if there's just one btrfs partition + for p in parts: + if p.fstype == 'btrfs': + for s in self.ks.handler.btrfs.btrfsList: + if s.subvol: + self.__instloop.add_subvolume(p.mountpoint, s.mountpoint, s.name) + try: self.__instloop.mount() except MountError as e: raise CreatorError("Failed mount disks : %s" % e) + if self.ks.handler.btrfs.btrfsList: + self.__instloop.setup_subvolumes() + self._create_mkinitrd_config() def _kernel_cmdline_append(self): diff --git a/appcreate/partitionedfs.py b/appcreate/partitionedfs.py index 4769ce9..86e709c 100644 --- a/appcreate/partitionedfs.py +++ b/appcreate/partitionedfs.py @@ -47,6 +47,7 @@ class PartitionedMount(Mount): 'offset': 0 } # Offset of next partition self.partitions = [] + self.subvolumes = [] self.mapped = False self.mountOrder = [] self.unmountOrder = [] @@ -64,6 +65,9 @@ class PartitionedMount(Mount): 'UUID': None, # UUID for partition 'num': None}) # Partition number + def add_subvolume(self, parent, mountpoint, name): + self.subvolumes.append({'parent': parent, 'mountpoint': mountpoint, 'name': name}) + def __format_disks(self): logging.debug("Formatting disks") for dev in list(self.disks.keys()): @@ -240,6 +244,20 @@ class PartitionedMount(Mount): pass def unmount(self): + if self.subvolumes: + ordered = [] + others = [] + for s in self.subvolumes: + if s['mountpoint'] == '/': + others.append(s) + else: + ordered.append(s) + + ordered += others + + for s in ordered: + subprocess.call(['umount', s['mountpoint']]) + for mp in self.unmountOrder: if mp == 'swap': continue @@ -256,6 +274,25 @@ class PartitionedMount(Mount): pass p['mount'] = None + def setup_subvolumes(self): + others = [] + ordered = [] + for s in self.subvolumes: + if s['mountpoint'] == '/': + ordered.append(s) + else: + others.append(s) + + ordered += others + for s in ordered: + base = "%s%s" % (self.mountdir, s['parent']) + path = "%s/%s" % (base, s['name']) + mountpath = "%s%s" % (self.mountdir, s['mountpoint']) + subprocess.call(['btrfs', 'subvol', 'create', path]) + subprocess.call(['mkdir', '-p', mountpath]) + device = subprocess.Popen(["findmnt", "-n", "-o", "SOURCE", base], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").strip() + subprocess.call(['mount', '-t', 'btrfs', '-o', 'subvol=%s' % s['name'], device, mountpath]) + def mount(self): for dev in list(self.disks.keys()): d = self.disks[dev]