From c210cdcb8f0883ac13a6ee22aebb8f01f3043e09 Mon Sep 17 00:00:00 2001 From: codefiles <11915375+codefiles@users.noreply.github.com> Date: Mon, 11 Mar 2024 03:09:26 -0400 Subject: Fix Btrfs mount options (#2404) --- archinstall/lib/disk/device_handler.py | 26 ++++++++++----------- archinstall/lib/disk/device_model.py | 36 ++++++---------------------- archinstall/lib/disk/partitioning_menu.py | 39 ++++++++++++++++++++++++------- archinstall/lib/disk/subvolume_menu.py | 27 ++------------------- 4 files changed, 52 insertions(+), 76 deletions(-) (limited to 'archinstall/lib/disk') diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py index 59ee150d..c06247e6 100644 --- a/archinstall/lib/disk/device_handler.py +++ b/archinstall/lib/disk/device_handler.py @@ -437,9 +437,19 @@ class DeviceHandler(object): if not luks_handler.mapper_dev: raise DiskError('Failed to unlock luks device') - self.mount(luks_handler.mapper_dev, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) + self.mount( + luks_handler.mapper_dev, + self._TMP_BTRFS_MOUNT, + create_target_mountpoint=True, + options=part_mod.mount_options + ) else: - self.mount(part_mod.safe_dev_path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True) + self.mount( + part_mod.safe_dev_path, + self._TMP_BTRFS_MOUNT, + create_target_mountpoint=True, + options=part_mod.mount_options + ) for sub_vol in part_mod.btrfs_subvols: debug(f'Creating subvolume: {sub_vol.name}') @@ -451,18 +461,6 @@ class DeviceHandler(object): SysCommand(f"btrfs subvolume create {subvol_path}") - if sub_vol.nodatacow: - try: - SysCommand(f'chattr +C {subvol_path}') - except SysCallError as err: - raise DiskError(f'Could not set nodatacow attribute at {subvol_path}: {err}') - - if sub_vol.compress: - try: - SysCommand(f'chattr +c {subvol_path}') - except SysCallError as err: - raise DiskError(f'Could not set compress attribute at {subvol_path}: {err}') - if luks_handler is not None and luks_handler.mapper_dev is not None: self.umount(luks_handler.mapper_dev) luks_handler.lock() diff --git a/archinstall/lib/disk/device_model.py b/archinstall/lib/disk/device_model.py index d4563faa..423c65e4 100644 --- a/archinstall/lib/disk/device_model.py +++ b/archinstall/lib/disk/device_model.py @@ -315,6 +315,11 @@ class Size: return self._normalize() >= other._normalize() +class BtrfsMountOption(Enum): + compress = 'compress=zstd' + nodatacow = 'nodatacow' + + @dataclass class _BtrfsSubvolumeInfo: name: Path @@ -458,8 +463,6 @@ class _DeviceInfo: class SubvolumeModification: name: Path mountpoint: Optional[Path] = None - compress: bool = False - nodatacow: bool = False @classmethod def from_existing_subvol_info(cls, info: _BtrfsSubvolumeInfo) -> SubvolumeModification: @@ -475,30 +478,10 @@ class SubvolumeModification: mountpoint = Path(entry['mountpoint']) if entry['mountpoint'] else None - compress = entry.get('compress', False) - nodatacow = entry.get('nodatacow', False) - - if compress and nodatacow: - raise ValueError('compress and nodatacow flags cannot be enabled simultaneously on a btfrs subvolume') - - mods.append( - SubvolumeModification( - entry['name'], - mountpoint, - compress, - nodatacow - ) - ) + mods.append(SubvolumeModification(entry['name'], mountpoint)) return mods - @property - def mount_options(self) -> List[str]: - options = [] - options += ['compress'] if self.compress else [] - options += ['nodatacow'] if self.nodatacow else [] - return options - @property def relative_mountpoint(self) -> Path: """ @@ -516,12 +499,7 @@ class SubvolumeModification: return False def json(self) -> Dict[str, Any]: - return { - 'name': str(self.name), - 'mountpoint': str(self.mountpoint), - 'compress': self.compress, - 'nodatacow': self.nodatacow - } + return {'name': str(self.name), 'mountpoint': str(self.mountpoint)} def table_data(self) -> Dict[str, Any]: return self.json() diff --git a/archinstall/lib/disk/partitioning_menu.py b/archinstall/lib/disk/partitioning_menu.py index a9478158..823605e3 100644 --- a/archinstall/lib/disk/partitioning_menu.py +++ b/archinstall/lib/disk/partitioning_menu.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Any, Dict, TYPE_CHECKING, List, Optional, Tuple from .device_model import PartitionModification, FilesystemType, BDevice, Size, Unit, PartitionType, PartitionFlag, \ - ModificationStatus, DeviceGeometry, SectorSize + ModificationStatus, DeviceGeometry, SectorSize, BtrfsMountOption from ..hardware import SysInfo from ..menu import Menu, ListManager, MenuSelection, TextInput from ..output import FormattedOutput, warn @@ -30,6 +30,7 @@ class PartitioningList(ListManager): 'mark_bootable': str(_('Mark/Unmark as bootable')), 'set_filesystem': str(_('Change filesystem')), 'btrfs_mark_compressed': str(_('Mark/Unmark as compressed')), # btrfs only + 'btrfs_mark_nodatacow': str(_('Mark/Unmark as nodatacow')), # btrfs only 'btrfs_set_subvolumes': str(_('Set subvolumes')), # btrfs only 'delete_partition': str(_('Delete partition')) } @@ -71,12 +72,17 @@ class PartitioningList(ListManager): self._actions['set_filesystem'], self._actions['mark_bootable'], self._actions['btrfs_mark_compressed'], + self._actions['btrfs_mark_nodatacow'], self._actions['btrfs_set_subvolumes'] ] # non btrfs partitions shouldn't get btrfs options if selection.fs_type != FilesystemType.Btrfs: - not_filter += [self._actions['btrfs_mark_compressed'], self._actions['btrfs_set_subvolumes']] + not_filter += [ + self._actions['btrfs_mark_compressed'], + self._actions['btrfs_mark_nodatacow'], + self._actions['btrfs_set_subvolumes'] + ] else: not_filter += [self._actions['assign_mountpoint']] @@ -122,7 +128,9 @@ class PartitioningList(ListManager): if fs_type == FilesystemType.Btrfs: entry.mountpoint = None case 'btrfs_mark_compressed' if entry: - self._set_compressed(entry) + self._toggle_mount_option(entry, BtrfsMountOption.compress) + case 'btrfs_mark_nodatacow' if entry: + self._toggle_mount_option(entry, BtrfsMountOption.nodatacow) case 'btrfs_set_subvolumes' if entry: self._set_btrfs_subvolumes(entry) case 'delete_partition' if entry: @@ -141,13 +149,28 @@ class PartitioningList(ListManager): else: return [d for d in data if d != entry] - def _set_compressed(self, partition: PartitionModification): - compression = 'compress=zstd' + def _toggle_mount_option( + self, + partition: PartitionModification, + option: BtrfsMountOption + ): + if option.value not in partition.mount_options: + if option == BtrfsMountOption.compress: + partition.mount_options = [ + o for o in partition.mount_options + if o != BtrfsMountOption.nodatacow.value + ] + + partition.mount_options = [ + o for o in partition.mount_options + if not o.startswith(BtrfsMountOption.compress.name) + ] - if compression in partition.mount_options: - partition.mount_options = [o for o in partition.mount_options if o != compression] + partition.mount_options.append(option.value) else: - partition.mount_options.append(compression) + partition.mount_options = [ + o for o in partition.mount_options if o != option.value + ] def _set_btrfs_subvolumes(self, partition: PartitionModification): partition.btrfs_subvols = SubvolumeMenu( diff --git a/archinstall/lib/disk/subvolume_menu.py b/archinstall/lib/disk/subvolume_menu.py index 2b70d7b2..48afa829 100644 --- a/archinstall/lib/disk/subvolume_menu.py +++ b/archinstall/lib/disk/subvolume_menu.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import Dict, List, Optional, Any, TYPE_CHECKING from .device_model import SubvolumeModification -from ..menu import Menu, TextInput, MenuSelectionType, ListManager +from ..menu import TextInput, ListManager from ..output import FormattedOutput if TYPE_CHECKING: @@ -36,23 +36,6 @@ class SubvolumeMenu(ListManager): def selected_action_display(self, subvolume: SubvolumeModification) -> str: return str(subvolume.name) - def _prompt_options(self, editing: Optional[SubvolumeModification] = None) -> List[str]: - preset_options = [] - if editing: - preset_options = editing.mount_options - - choice = Menu( - str(_("Select the desired subvolume options ")), - ['nodatacow', 'compress'], - skip=True, - preset_values=preset_options, - ).run() - - if choice.type_ == MenuSelectionType.Selection: - return choice.value # type: ignore - - return [] - def _add_subvolume(self, editing: Optional[SubvolumeModification] = None) -> Optional[SubvolumeModification]: name = TextInput(f'\n\n{_("Subvolume name")}: ', editing.name if editing else '').run() @@ -64,13 +47,7 @@ class SubvolumeMenu(ListManager): if not mountpoint: return None - options = self._prompt_options(editing) - - subvolume = SubvolumeModification(Path(name), Path(mountpoint)) - subvolume.compress = 'compress' in options - subvolume.nodatacow = 'nodatacow' in options - - return subvolume + return SubvolumeModification(Path(name), Path(mountpoint)) def handle_action( self, -- cgit v1.2.3-54-g00ecf