diff --git a/subiquity/common/filesystem/manipulator.py b/subiquity/common/filesystem/manipulator.py index f9dfc6bb..375ba2ac 100644 --- a/subiquity/common/filesystem/manipulator.py +++ b/subiquity/common/filesystem/manipulator.py @@ -23,6 +23,20 @@ from subiquity.models.filesystem import Partition, align_up log = logging.getLogger("subiquity.common.filesystem.manipulator") +zfs_boot_features = [ + "async_destroy", + "bookmarks", + "embedded_data", + "empty_bpobj", + "enabled_txg", + "extensible_dataset", + "filesystem_limits", + "hole_birth", + "large_blocks", + "lz4_compress", + "spacemap_histogram", +] + class FilesystemManipulator: def create_mount(self, fs, spec): @@ -158,21 +172,33 @@ class FilesystemManipulator: delete_lvm_partition = delete_logical_volume - def create_zpool(self, device, pool, mountpoint): + def create_zpool(self, device, pool, mountpoint, boot=False, canmount="on"): fs_properties = dict( + atime=None, acltype="posixacl", - relatime="on", - canmount="on", - compression="gzip", + canmount=canmount, + compression="lz4", devices="off", + normalization="formD", + relatime="on", + sync="standard", xattr="sa", ) - pool_properties = dict(ashift=12) - self.model.add_zpool( + pool_properties = dict(ashift=12, autotrim="on", version=None) + default_features = True + if boot: + default_features = False + for feat in zfs_boot_features: + pool_properties[f"feature@{feat}"] = "enabled" + else: + fs_properties["dnodesize"] = "auto" + + return self.model.add_zpool( device, pool, mountpoint, + default_features=default_features, fs_properties=fs_properties, pool_properties=pool_properties, ) diff --git a/subiquity/server/controllers/filesystem.py b/subiquity/server/controllers/filesystem.py index 13dfa686..ce876819 100644 --- a/subiquity/server/controllers/filesystem.py +++ b/subiquity/server/controllers/filesystem.py @@ -81,7 +81,7 @@ from subiquitycore.async_helpers import ( ) from subiquitycore.context import with_context from subiquitycore.lsb_release import lsb_release -from subiquitycore.utils import arun_command, run_command +from subiquitycore.utils import arun_command, gen_zsys_uuid, run_command log = logging.getLogger("subiquity.server.controllers.filesystem") block_discover_log = logging.getLogger("block-discover") @@ -480,7 +480,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator): part_align = device.alignment_data().part_align bootfs_size = align_up(sizes.get_bootfs_size(gap.size), part_align) gap_boot, gap_rest = gap.split(bootfs_size) - bpool_part = self.create_partition(device, gap_boot, dict(fstype=None)) + bpart = self.create_partition(device, gap_boot, dict(fstype=None)) avail = gap_rest.size - self._info.min_size swap_size = swap.suggested_swapsize(avail=avail) @@ -490,10 +490,33 @@ class FilesystemController(SubiquityController, FilesystemManipulator): gap = gap_rootfs else: gap = gap_rest - rpool_part = self.create_partition(device, gap, dict(fstype=None)) + rpart = self.create_partition(device, gap, dict(fstype=None)) - self.create_zpool(bpool_part, "bpool", "/boot") - self.create_zpool(rpool_part, "rpool", "/") + uuid = gen_zsys_uuid() + + bpool = self.create_zpool(bpart, "bpool", "/boot", boot=True, canmount="off") + bpool.create_zfs("BOOT", canmount="off", mountpoint="none") + bpool.create_zfs(f"BOOT/ubuntu_{uuid}", mountpoint="/boot") + + rpool = self.create_zpool(rpart, "rpool", "/", canmount="off") + rpool.create_zfs("ROOT", canmount="off", mountpoint="none") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}", mountpoint="/") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var", canmount="off") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/lib") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/lib/AccountsService") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/lib/apt") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/lib/dpkg") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/lib/NetworkManager") + + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/srv") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/usr", canmount="off") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/usr/local") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/games") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/log") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/mail") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/snap") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/spool") + rpool.create_zfs(f"ROOT/ubuntu_{uuid}/var/www") @functools.singledispatchmethod def start_guided(self, target: GuidedStorageTarget, disk: ModelDisk) -> gaps.Gap: diff --git a/subiquity/server/controllers/tests/test_filesystem.py b/subiquity/server/controllers/tests/test_filesystem.py index 40fa0036..c9734bdd 100644 --- a/subiquity/server/controllers/tests/test_filesystem.py +++ b/subiquity/server/controllers/tests/test_filesystem.py @@ -490,11 +490,15 @@ class TestGuided(IsolatedAsyncioTestCase): self.assertFalse(root.preserve) self.assertEqual("swap", swap.fs().fstype) [rpool] = self.model._all(type="zpool", pool="rpool") - self.assertEqual("/", rpool.path) + self.assertIsNone(rpool.path) self.assertEqual([root], rpool.vdevs) [bpool] = self.model._all(type="zpool", pool="bpool") - self.assertEqual("/boot", bpool.path) + self.assertIsNone(bpool.path) self.assertEqual([boot], bpool.vdevs) + zfs_rootfs = self.model._mount_for_path("/") + self.assertEqual("zfs", zfs_rootfs.type) + zfs_boot = self.model._mount_for_path("/boot") + self.assertEqual("zfs", zfs_boot.type) async def test_guided_zfs_BIOS_MSDOS(self): await self._guided_setup(Bootloader.BIOS, "msdos") @@ -512,11 +516,15 @@ class TestGuided(IsolatedAsyncioTestCase): self.assertFalse(root.preserve) self.assertEqual("swap", swap.fs().fstype) [rpool] = self.model._all(type="zpool", pool="rpool") - self.assertEqual("/", rpool.path) + self.assertIsNone(rpool.path) self.assertEqual([root], rpool.vdevs) [bpool] = self.model._all(type="zpool", pool="bpool") - self.assertEqual("/boot", bpool.path) + self.assertIsNone(bpool.path) self.assertEqual([boot], bpool.vdevs) + zfs_rootfs = self.model._mount_for_path("/") + self.assertEqual("zfs", zfs_rootfs.type) + zfs_boot = self.model._mount_for_path("/boot") + self.assertEqual("zfs", zfs_boot.type) async def _guided_side_by_side(self, bl, ptable): await self._guided_setup(bl, ptable, storage_version=2)