diff --git a/src/modules/fstab/main.py b/src/modules/fstab/main.py index 6977ccad1..b6d7a4b2a 100644 --- a/src/modules/fstab/main.py +++ b/src/modules/fstab/main.py @@ -183,37 +183,19 @@ class FstabGenerator(object): print(FSTAB_HEADER, file=fstab_file) for partition in self.partitions: - # Special treatment for a btrfs root with @, @home and @swap - # subvolumes + # Special treatment for a btrfs subvolumes if (partition["fs"] == "btrfs" and partition["mountPoint"] == "/"): - output = subprocess.check_output(['btrfs', - 'subvolume', - 'list', - self.root_mount_point]) - output_lines = output.splitlines() - for line in output_lines: - if line.endswith(b'path @'): - root_entry = partition - root_entry["subvol"] = "@" - dct = self.generate_fstab_line_info(root_entry) - if dct: + # Subvolume list has been created in mount.conf and curated in mount module, + # so all subvolumes here should be safe to add to fstab + btrfs_subvolumes = libcalamares.globalstorage.value("btrfsSubvolumes") + for s in btrfs_subvolumes: + mount_entry = partition + mount_entry["mountPoint"] = s["mountPoint"] + mount_entry["subvol"] = s["subvolume"] + dct = self.generate_fstab_line_info(mount_entry) + if dct: self.print_fstab_line(dct, file=fstab_file) - elif line.endswith(b'path @home'): - home_entry = partition - home_entry["mountPoint"] = "/home" - home_entry["subvol"] = "@home" - dct = self.generate_fstab_line_info(home_entry) - if dct: - self.print_fstab_line(dct, file=fstab_file) - elif line.endswith(b'path @swap'): - swap_part_entry = partition - swap_part_entry["mountPoint"] = "/swap" - swap_part_entry["subvol"] = "@swap" - dct = self.generate_fstab_line_info(swap_part_entry) - if dct: - self.print_fstab_line(dct, file=fstab_file) - else: dct = self.generate_fstab_line_info(partition) if dct: diff --git a/src/modules/mount/main.py b/src/modules/mount/main.py index 3982176df..07166dd75 100644 --- a/src/modules/mount/main.py +++ b/src/modules/mount/main.py @@ -32,9 +32,6 @@ def pretty_name(): def mount_partition(root_mount_point, partition, partitions): """ Do a single mount of @p partition inside @p root_mount_point. - - The @p partitions are used to handle btrfs special-cases: - then subvolumes are created for root and home. """ # Create mount point with `+` rather than `os.path.join()` because # `partition["mountPoint"]` starts with a '/'. @@ -74,36 +71,29 @@ def mount_partition(root_mount_point, partition, partitions): partition.get("options", "")) != 0: libcalamares.utils.warning("Cannot mount {}".format(device)) - # If the root partition is btrfs, we create a subvolume "@" - # for the root mount point. - # If a separate /home partition isn't defined, we also create - # a subvolume "@home". - # If a swapfile is used, we also create a subvolume "@swap". - # Finally we remount all of the above on the correct paths. + # Special handling for btrfs subvolumes. Create the subvolumes listed in mount.conf if fstype == "btrfs" and partition["mountPoint"] == '/': - has_home_mount_point = False + # Root has been mounted to btrfs volume -> create subvolumes from configuration + btrfs_subvolumes = libcalamares.job.configuration.get("btrfsSubvolumes") or [] + subvolume_mountpoints = [d['mountPoint'] for d in btrfs_subvolumes] + # Check if listed mountpoints besides / are already present and don't create subvolume for those for p in partitions: if "mountPoint" not in p or not p["mountPoint"]: continue - if p["mountPoint"] == "/home": - has_home_mount_point = True - break - needs_swap_subvolume = False + if p["mountPoint"] in subvolume_mountpoints and p["mountPoint"] != '/': + btrfs_subvolumes = [d for d in btrfs_subvolumes if d['mountPoint'] != p["mountPoint"]] + # Check if we need a subvolume for swap file swap_choice = global_storage.value( "partitionChoices" ) if swap_choice: swap_choice = swap_choice.get( "swap", None ) if swap_choice and swap_choice == "file": - needs_swap_subvolume = True - - subprocess.check_call(['btrfs', 'subvolume', 'create', - root_mount_point + '/@']) - - if not has_home_mount_point: + btrfs_subvolumes.append({'mountPoint': '/swap', 'subvolume': '/@swap'}) + # Store created list in global storage so it can be used in the fstab module + libcalamares.globalstorage.insert("btrfsSubvolumes", btrfs_subvolumes) + # Create the subvolumes that are in the completed list + for s in btrfs_subvolumes: subprocess.check_call(['btrfs', 'subvolume', 'create', - root_mount_point + '/@home']) - if needs_swap_subvolume: - subprocess.check_call(['btrfs', 'subvolume', 'create', - root_mount_point + '/@swap']) + root_mount_point + s['subvolume']]) subprocess.check_call(["umount", "-v", root_mount_point]) @@ -112,24 +102,14 @@ def mount_partition(root_mount_point, partition, partitions): if "luksMapperName" in partition: device = os.path.join("/dev/mapper", partition["luksMapperName"]) - if libcalamares.utils.mount(device, - mount_point, + # Mount the subvolumes + for s in btrfs_subvolumes: + mount_option = "subvol={}".format(s['subvolume']) + subvolume_mountpoint = mount_point[:-1] + s['mountPoint'] + if libcalamares.utils.mount(device, + subvolume_mountpoint, fstype, - ",".join(["subvol=@", partition.get("options", "")])) != 0: - libcalamares.utils.warning("Cannot mount {}".format(device)) - - if not has_home_mount_point: - if libcalamares.utils.mount(device, - root_mount_point + "/home", - fstype, - ",".join(["subvol=@home", partition.get("options", "")])) != 0: - libcalamares.utils.warning("Cannot mount {}".format(device)) - - if needs_swap_subvolume: - if libcalamares.utils.mount(device, - root_mount_point + "/swap", - fstype, - ",".join(["subvol=@swap", partition.get("options", "")])) != 0: + ",".join([mount_option, partition.get("options", "")])) != 0: libcalamares.utils.warning("Cannot mount {}".format(device)) diff --git a/src/modules/mount/mount.conf b/src/modules/mount/mount.conf index 3a117d32c..6168e97cc 100644 --- a/src/modules/mount/mount.conf +++ b/src/modules/mount/mount.conf @@ -40,3 +40,17 @@ extraMountsEfi: - device: efivarfs fs: efivarfs mountPoint: /sys/firmware/efi/efivars + +# Btrfs subvolumes to create if root filesystem is on btrfs volume. +# If mountpoint is mounted already to another partition, it is ignored. +# Separate subvolume for swapfile is handled separately and automatically. + +btrfsSubvolumes: + - mountPoint: / + subvolume: /@ + - mountPoint: /home + subvolume: /@home + - mountPoint: /var/cache + subvolume: /@cache + - mountPoint: /var/log + subvolume: /@log \ No newline at end of file diff --git a/src/modules/mount/mount.schema.yaml b/src/modules/mount/mount.schema.yaml index 2d5e4d4a0..fb5dfb69c 100644 --- a/src/modules/mount/mount.schema.yaml +++ b/src/modules/mount/mount.schema.yaml @@ -29,3 +29,12 @@ properties: mountPoint: { type: string } options: { type: string } required: [ device, mountPoint ] + btrfsSubvolumes: + type: array + items: + type: object + additionalProperties: false + properties: + mountPoint: { type: string } + subvolume: { type: string } + required: [ subvolume, mountPoint ]