From bf47e761b041c55aa880650759a311e225e24bbe Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Wed, 17 Jul 2019 12:15:22 +0200 Subject: [PATCH 1/2] mount: Make sure extra mounts are mounted right after / When the rootfs partition is read-only, mount points for the other partitions cannot be created, therefore they need to be created in a tmpfs, already mounted somewhere in `/`. However, the extra mounts are only mounted at the end, which causes an error as no tmpfs is currently mounted. This patch makes sure all extra mounts are mounted right after the `/` partition, allowing the use of a read-only rootfs. Signed-off-by: Arnaud Ferraris --- src/modules/mount/main.py | 184 +++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/src/modules/mount/main.py b/src/modules/mount/main.py index ed649aead..b093d0dfb 100644 --- a/src/modules/mount/main.py +++ b/src/modules/mount/main.py @@ -37,104 +37,109 @@ _ = gettext.translation("calamares-python", def pretty_name(): return _("Mounting partitions.") +def mount_part(root_mount_point, partition, partitions): + # Create mount point with `+` rather than `os.path.join()` because + # `partition["mountPoint"]` starts with a '/'. + raw_mount_point = partition["mountPoint"] + mount_point = root_mount_point + raw_mount_point -def mount_partitions(root_mount_point, partitions): + # Ensure that the created directory has the correct SELinux context on + # SELinux-enabled systems. + os.makedirs(mount_point, exist_ok=True) + subprocess.call(['chcon', '--reference=' + raw_mount_point, + mount_point]) + + fstype = partition.get("fs", "").lower() + + if fstype == "fat16" or fstype == "fat32": + fstype = "vfat" + + if "luksMapperName" in partition: + libcalamares.utils.debug( + "about to mount {!s}".format(partition["luksMapperName"])) + libcalamares.utils.mount( + "/dev/mapper/{!s}".format(partition["luksMapperName"]), + mount_point, + fstype, + partition.get("options", ""), + ) + + else: + libcalamares.utils.mount(partition["device"], + mount_point, + fstype, + partition.get("options", ""), + ) + + # 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". + # Finally we remount all of the above on the correct paths. + if fstype == "btrfs" and partition["mountPoint"] == '/': + has_home_mount_point = False + for p in partitions: + if "mountPoint" not in p or not p["mountPoint"]: + continue + if p["mountPoint"] == "/home": + has_home_mount_point = True + break + + subprocess.check_call(['btrfs', 'subvolume', 'create', + root_mount_point + '/@']) + + if not has_home_mount_point: + subprocess.check_call(['btrfs', 'subvolume', 'create', + root_mount_point + '/@home']) + + subprocess.check_call(["umount", "-v", root_mount_point]) + + if "luksMapperName" in partition: + libcalamares.utils.mount( + "/dev/mapper/{!s}".format(partition["luksMapperName"]), + mount_point, + fstype, + ",".join( + ["subvol=@", partition.get("options", "")]), + ) + if not has_home_mount_point: + libcalamares.utils.mount( + "/dev/mapper/{!s}".format(partition["luksMapperName"]), + root_mount_point + "/home", + fstype, + ",".join( + ["subvol=@home", partition.get("options", "")]), + ) + else: + libcalamares.utils.mount( + partition["device"], + mount_point, + fstype, + ",".join(["subvol=@", partition.get("options", "")]), + ) + if not has_home_mount_point: + libcalamares.utils.mount( + partition["device"], + root_mount_point + "/home", + fstype, + ",".join( + ["subvol=@home", partition.get("options", "")]), + ) + +def mount_partitions(root_mount_point, partitions, extra_mounts=None): """ Pass back mount point and filesystem for each partition. :param root_mount_point: :param partitions: + :param extra_mounts: """ for partition in partitions: if "mountPoint" not in partition or not partition["mountPoint"]: continue - # Create mount point with `+` rather than `os.path.join()` because - # `partition["mountPoint"]` starts with a '/'. - raw_mount_point = partition["mountPoint"] - mount_point = root_mount_point + raw_mount_point - - # Ensure that the created directory has the correct SELinux context on - # SELinux-enabled systems. - os.makedirs(mount_point, exist_ok=True) - subprocess.call(['chcon', '--reference=' + raw_mount_point, - mount_point]) - - fstype = partition.get("fs", "").lower() - - if fstype == "fat16" or fstype == "fat32": - fstype = "vfat" - - if "luksMapperName" in partition: - libcalamares.utils.debug( - "about to mount {!s}".format(partition["luksMapperName"])) - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - mount_point, - fstype, - partition.get("options", ""), - ) - - else: - libcalamares.utils.mount(partition["device"], - mount_point, - fstype, - partition.get("options", ""), - ) - - # 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". - # Finally we remount all of the above on the correct paths. - if fstype == "btrfs" and partition["mountPoint"] == '/': - has_home_mount_point = False - for p in partitions: - if "mountPoint" not in p or not p["mountPoint"]: - continue - if p["mountPoint"] == "/home": - has_home_mount_point = True - break - - subprocess.check_call(['btrfs', 'subvolume', 'create', - root_mount_point + '/@']) - - if not has_home_mount_point: - subprocess.check_call(['btrfs', 'subvolume', 'create', - root_mount_point + '/@home']) - - subprocess.check_call(["umount", "-v", root_mount_point]) - - if "luksMapperName" in partition: - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - mount_point, - fstype, - ",".join( - ["subvol=@", partition.get("options", "")]), - ) - if not has_home_mount_point: - libcalamares.utils.mount( - "/dev/mapper/{!s}".format(partition["luksMapperName"]), - root_mount_point + "/home", - fstype, - ",".join( - ["subvol=@home", partition.get("options", "")]), - ) - else: - libcalamares.utils.mount( - partition["device"], - mount_point, - fstype, - ",".join(["subvol=@", partition.get("options", "")]), - ) - if not has_home_mount_point: - libcalamares.utils.mount( - partition["device"], - root_mount_point + "/home", - fstype, - ",".join( - ["subvol=@home", partition.get("options", "")]), - ) + mount_part(root_mount_point, partition, partitions) + if partition["mountPoint"] is "/" and extra_mounts is not None: + mount_partitions(root_mount_point, extra_mounts) def run(): @@ -160,8 +165,7 @@ def run(): # Sort by mount points to ensure / is mounted before the rest partitions.sort(key=lambda x: x["mountPoint"]) - mount_partitions(root_mount_point, partitions) - mount_partitions(root_mount_point, extra_mounts) + mount_partitions(root_mount_point, partitions, extra_mounts) all_extra_mounts = extra_mounts if libcalamares.globalstorage.value("firmwareType") == "efi": From 257f5da1af78747759dc580eec27a6d1667f2304 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Wed, 14 Aug 2019 09:58:40 +0200 Subject: [PATCH 2/2] mount: Use a single partitions list sorted by mount point Instead of having a special case for extra mounts to be processed right after the rootfs, a better approach is to add them to the partitions list, and then sort the list by mount point. This way, we make sure every partition is mounted right when it is needed: `/` is obviously mounted first, `/run` is mounted before `/run/udev`, and so on. The overall process is therefore more generic and should suit all use-cases. Signed-off-by: Arnaud Ferraris --- src/modules/mount/main.py | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/modules/mount/main.py b/src/modules/mount/main.py index b093d0dfb..1c684c43f 100644 --- a/src/modules/mount/main.py +++ b/src/modules/mount/main.py @@ -37,7 +37,7 @@ _ = gettext.translation("calamares-python", def pretty_name(): return _("Mounting partitions.") -def mount_part(root_mount_point, partition, partitions): +def mount_partition(root_mount_point, partition, partitions): # Create mount point with `+` rather than `os.path.join()` because # `partition["mountPoint"]` starts with a '/'. raw_mount_point = partition["mountPoint"] @@ -126,21 +126,6 @@ def mount_part(root_mount_point, partition, partitions): ["subvol=@home", partition.get("options", "")]), ) -def mount_partitions(root_mount_point, partitions, extra_mounts=None): - """ - Pass back mount point and filesystem for each partition. - - :param root_mount_point: - :param partitions: - :param extra_mounts: - """ - for partition in partitions: - if "mountPoint" not in partition or not partition["mountPoint"]: - continue - mount_part(root_mount_point, partition, partitions) - if partition["mountPoint"] is "/" and extra_mounts is not None: - mount_partitions(root_mount_point, extra_mounts) - def run(): """ @@ -163,16 +148,21 @@ def run(): if not extra_mounts and not extra_mounts_efi: libcalamares.utils.warning("No extra mounts defined. Does mount.conf exist?") - # Sort by mount points to ensure / is mounted before the rest - partitions.sort(key=lambda x: x["mountPoint"]) - mount_partitions(root_mount_point, partitions, extra_mounts) - - all_extra_mounts = extra_mounts if libcalamares.globalstorage.value("firmwareType") == "efi": - mount_partitions(root_mount_point, extra_mounts_efi) - all_extra_mounts.extend(extra_mounts_efi) + extra_mounts.extend(extra_mounts_efi) + + # Add extra mounts to the partitions list and sort by mount points. + # This way, we ensure / is mounted before the rest, and every mount point + # is created on the right partition (e.g. if a partition is to be mounted + # under /tmp, we make sure /tmp is mounted before the partition) + partitions.extend(extra_mounts) + partitions.sort(key=lambda x: x["mountPoint"]) + for partition in partitions: + if "mountPoint" not in partition or not partition["mountPoint"]: + continue + mount_partition(root_mount_point, partition, partitions) libcalamares.globalstorage.insert("rootMountPoint", root_mount_point) # Remember the extra mounts for the unpackfs module - libcalamares.globalstorage.insert("extraMounts", all_extra_mounts) + libcalamares.globalstorage.insert("extraMounts", extra_mounts)