Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos: Support systemd-gpt-auto-root #282022

Merged
merged 2 commits into from
Mar 18, 2024
Merged

Conversation

ElvishJerricco
Copy link
Contributor

@ElvishJerricco ElvishJerricco commented Jan 19, 2024

Description of changes

Rather than removing the broken generator in #277703, why not just support it?

Note: You must add your desired file system type to boot.initrd.supportedFilesystems.

Fixes #293586, #276374

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

@ElvishJerricco ElvishJerricco requested review from a team and dasJ as code owners January 19, 2024 10:42
philiptaron added a commit to philiptaron/flock.nix that referenced this pull request Jan 19, 2024
I had to run `sudo sgdisk --typecode=2:4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 /dev/nvme3n1`
in order to cause the right partition type code to be applied to the correct partition,
so that `systemd-gpt-auto-generator` would detect it at boot time.
@philiptaron
Copy link
Contributor

philiptaron/flock.nix@58dfcb6 is me testing this out on my real machine; it works great.

I had to do sgdisk --typecode=2:4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 /dev/nvme3n1 as the type of the partition wasn't right at my initial format time.

Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like having systemd-gpt-auto-generator (and the other generators) find and detect partitions.

nixos/modules/system/boot/stage-1.nix Outdated Show resolved Hide resolved
nixos/modules/system/boot/systemd/initrd.nix Show resolved Hide resolved
nixos/modules/tasks/filesystems.nix Outdated Show resolved Hide resolved
@philiptaron
Copy link
Contributor

I'd love to see this committed -- what's outstanding, do you think, @ElvishJerricco?

@ElvishJerricco
Copy link
Contributor Author

The only thing that gives me pause is the handling of root=, and how it relates to #285254. I think we might instead want something like

options.boot.initrd.rootFS = mkOption {
  type = types.enum [ "fstab" "gpt-auto" ];
};

so that it can be extended with the other options that systemd supports in the future, rather than having this boot.initrd.gptAutoRoot.enable option.

@philiptaron
Copy link
Contributor

The only thing that gives me pause is the handling of root=, and how it relates to #285254. I think we might instead want something like

options.boot.initrd.rootFS = mkOption {
  type = types.enum [ "fstab" "gpt-auto" ];
};

so that it can be extended with the other options that systemd supports in the future, rather than having this boot.initrd.gptAutoRoot.enable option.

That makes sense. It would default to fstab, you think? Or to something else?

@msanft
Copy link
Contributor

msanft commented Feb 9, 2024

The only thing that gives me pause is the handling of root=, and how it relates to #285254. I think we might instead want something like

options.boot.initrd.rootFS = mkOption {
  type = types.enum [ "fstab" "gpt-auto" ];
};

so that it can be extended with the other options that systemd supports in the future, rather than having this boot.initrd.gptAutoRoot.enable option.

I agree here. There are various methods of how systemd can setup the mounts, and I think rather than having one or another (i.e. fileSystems, systemd-veritysetup, or systemd-gpt-auto-root), this might be a more future-proof solution.

Comment on lines 340 to 345
{
assertion = config.boot.initrd.gptAutoRoot.enable -> config.boot.loader.systemd-boot.enable;
message = ''
'boot.initrd.gptAutoRoot.enable' requires systemd-boot.
'';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the case if booting from a UKI with systemd-stub, where it will take care of setting up the EFI variables for the root disk: https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html#LoaderDevicePartUUID

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we don't include ways of using systemd-stub at this time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we have a builder for ukify? We maybe can't properly check if a UKI is used, but then this assertion should be removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree with @msanft we should not assert on that. Booting without enabling sd-boot via the module system is an actual use-case we have for appliance images.

@arianvp
Copy link
Member

arianvp commented Feb 9, 2024

options.boot.initrd.rootFS = mkOption {
type = types.enum [ "fstab" "gpt-auto" ];
};

This doesn't work. root= parameter supports way more values! like root=/dev/vda2 root=dhcpv6 root=nfs etc.

the root= parameter furthermore is also parsed by the kernel and NFS daemons.

I personally use root=tmpfs in my own setup.

@ElvishJerricco
Copy link
Contributor Author

@arianvp But we don't support other things in root= right now. Currently, we require the root fs in SYSTEMD_SYSROOT_FSTAB, and having that along with root= on the cmdline leads to failed boots.

Copy link
Contributor

@nikstur nikstur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really cool! The assertion in filesystems.nix on whether the user explicitly includes the rootfs has been bugging me for a while now!

Comment on lines 340 to 345
{
assertion = config.boot.initrd.gptAutoRoot.enable -> config.boot.loader.systemd-boot.enable;
message = ''
'boot.initrd.gptAutoRoot.enable' requires systemd-boot.
'';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree with @msanft we should not assert on that. Booting without enabling sd-boot via the module system is an actual use-case we have for appliance images.

nixos/modules/tasks/filesystems.nix Outdated Show resolved Hide resolved
nixos/modules/tasks/filesystems.nix Outdated Show resolved Hide resolved
philiptaron added a commit to philiptaron/flock.nix that referenced this pull request Mar 3, 2024
Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple notes.

  1. If boot.initrd.supportedFilesystems = ["ext4"]; (for example) is not set, systemd-gpt-auto-generator will fail to find the root file system. That's a sharp edge, and one that almost made me believe that the thing didn't work.
  2. I had to edit the disk earlier in order to set the correct GUID (sgdisk --typecode=2:4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 /dev/nvme3n1) as the type of the partition wasn't right at my initial format time. That's a sharp edge.
  3. I note this in the logs from this boot:
Mar 03 14:46:35 zebul systemd-gpt-auto-generator[577]: Failed to chase block device, ignoring: No such file or directory
Mar 03 14:46:35 zebul systemd-gpt-auto-generator[577]: Probed fstype 'ext4' on partition /dev/disk/by-diskseq/1-part2.
Mar 03 14:46:35 zebul systemd-gpt-auto-generator[577]: Reading EFI variable /sys/firmware/efi/efivars/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f.
Mar 03 14:46:35 zebul systemd-gpt-auto-generator[577]: Root partition not marked for growing the file system in the GPT partition table, not generating drop-in for systemd-growfs-root.service.

I don't think any of those logs are a problem, just noting them as "expected output" from the tool.

@@ -688,7 +688,7 @@ in

config = mkIf config.boot.initrd.enable {
assertions = [
{ assertion = any (fs: fs.mountPoint == "/") fileSystems;
{ assertion = !config.boot.initrd.systemd.enable -> any (fs: fs.mountPoint == "/") fileSystems;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If config.boot.initrd.systemd.enable is set, there is no assertion. If config.boot.initrd.systemd.enable is not set, there is an assertion when no "/" mountpoint is set.

Comment on lines +360 to +361
assertion = cfg.root == "fstab" -> any (fs: fs.mountPoint == "/") (builtins.attrValues config.fileSystems);
message = "The ‘fileSystems’ option does not specify your root file system.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, and here's the other assertion.

Copy link
Contributor

@msanft msanft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think this is a good solution that can also serve as a ground for future additions, e.g. using systemd-veritysetup-generator.

I actually think this should work with all other systemd generators that are capable of setting up the root mounts, as even if some have other options (e.g. roothash for systemd-veritysetup-generator), all that I have looked at seem to be fine with additionally having root.

@msanft
Copy link
Contributor

msanft commented Mar 4, 2024

2. I had to edit the disk earlier in order to set the correct GUID (sgdisk --typecode=2:4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 /dev/nvme3n1) as the type of the partition wasn't right at my initial format time. That's a sharp edge.

Yes, might not hurt to additionally document the requirement for DDI-conformance when using this, either in the release notes or the module documentation.

Copy link
Contributor

@nikstur nikstur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's fix the merge conflict and this is good to go on my end.

@ElvishJerricco
Copy link
Contributor Author

This also happens to fix #276374. It's easy to modify the hibernate.nix test to reflect this (two line diff). Should that be included in this PR?

So that resumeDevice isn't needed to make systemd stage 1 work.
@ElvishJerricco
Copy link
Contributor Author

@ofborg test hibernate hibernate-systemd-stage-1

Copy link
Contributor

@r-vdp r-vdp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this on my systems that are all running impermanence with a tmpfs as root to make sure that that use case still works, and I haven't encountered any issues.

@nikstur nikstur merged commit a1c4f0a into NixOS:master Mar 18, 2024
24 checks passed
Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting this in!

@@ -371,7 +389,12 @@ in {
"autofs"
# systemd-cryptenroll
] ++ lib.optional cfg.enableTpm2 "tpm-tis"
++ lib.optional (cfg.enableTpm2 && !(pkgs.stdenv.hostPlatform.isRiscV64 || pkgs.stdenv.hostPlatform.isArmv7)) "tpm-crb";
++ lib.optional (cfg.enableTpm2 && !(pkgs.stdenv.hostPlatform.isRiscV64 || pkgs.stdenv.hostPlatform.isArmv7)) "tpm-crb"
++ lib.optional cfg.package.withEfi "efivarfs";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be conditional on cfg.root == "gpt-auto"? I don't see why this feature should add kernel modules for users who don't enable it. Adding it is problematic for me because it doesn't exist on armv6l.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lopsided98 efivarfs is useful for a few features, notably including hibernation. I'd rather disable it on platforms that don't support it than require it to be explicitly enabled.

If efivarfs doesn't exist on a platform, then I'm surprised we build systemd with withEfi = true. Maybe that's the change we should make?

Copy link
Contributor

@lopsided98 lopsided98 Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withEfi defaults to stdenv.hostPlatform.isEfi. In practice, isEfi means "platforms where systemd EFI support can be built". There are unlikely to be any armv6l systems that use EFI, so it would be fine to remove it from isEfi, but I'm still not super happy with tying efivarfs in the initrd to systemd EFI support.

There is no way to override boot.initrd.availableKernelModules to remove an item, so we should be careful about what is added unconditionally. If someone wants to disable EFI support in their kernel for whatever reason, they also have to override systemd and rebuild the world. If hibernation needs efivarsfs, it should be automatically enabled in that module as well. I actually have a similar objection to autofs, but it has never caused enough problems for me to try fixing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lopsided98

  1. You don't have to rebuild the world to override systemd. You can just set systemd.package = pkgs.systemd.override { withEfi = false; };
  2. Hibernation isn't really something we have a module for. It's just something systemd is able to do. So simply having systemctl means a user is able to attempt to hibernate.

We could have an option like boot.initrd.systemd.efiSupport with a default of cfg.package.withEfi so that it can be reasonably overridden. I still think this is wrong, however. Ideally, a system that doesn't have EFI should have systemd.package set to a systemd override with EFI disabled.

Alternatively, we could have a new option like boot.initrd.optionalKernelModules which lists modules that should be included if the kernel build has them. This would be helpful in other situations as well. Like the all-hardware.nix profile breaks when you build with the RPi kernel, since it disables many of the modules that all-hardware.nix has in availableKernelModules.

Copy link
Member

@arianvp arianvp Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually have a similar objection to autofs, but it has never caused enough problems for me to try fixing it.

autofs is required for systemd to boot as far as I am aware. as systemd ships with some required .automount units

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually have a similar objection to autofs, but it has never caused enough problems for me to try fixing it.

autofs is required for systemd to boot as far as I am aware. as systemd ships with some required .automount units

From the docs on CONFIG_AUTOFS_FS:

The automounter is a tool to automatically mount remote file systems on demand. This implementation is partially kernel-based to reduce overhead in the already-mounted case; this is unlike the BSD automounter (amd), which is a pure user space daemon.

To use the automounter you need the user-space tools from https://www.kernel.org/pub/linux/daemons/autofs/; you also want to answer Y to "NFS file system support", below.

To compile this support as a module, choose M here: the module will be called autofs.

If you are not a part of a fairly large, distributed network or don't have a laptop which needs to dynamically reconfigure to the local network, you probably do not need an automounter, and can say N here.

I only see one .automount unit that ships with systemd and it looks trivially replaceable.

philiptaron added a commit to philiptaron/flock.nix that referenced this pull request Mar 21, 2024
philiptaron added a commit to philiptaron/flock.nix that referenced this pull request Mar 22, 2024
…for the forseeable."

This reverts commit 4b2c89e.

Testing to see if it's what's causing my activation woes.
@philiptaron
Copy link
Contributor

philiptaron commented Mar 22, 2024

It brings me no pleasure to report that setting gpt-auto broke activation. When I booted my system that has the root detected through systemd-gpt-auto-root, it no longer updates /etc to reflect what's in the system closure.

$ journalctl -b -10 -u initrd-nixos-activation.service
Mar 22 09:37:40 localhost systemd[1]: initrd-nixos-activation.service: starting held back, waiting for: initrd-fs.target
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: AssertPathExists=/etc/initrd-release succeeded.
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Will spawn child (service_enter_start): /nix/store/57zdzvsd1wcsfxbdrkpdz7hx35jb0ds9-unit-script-initrd-nixos-activation-start/bin/initrd-nixos-activation-start
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Passing 0 fds to service
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: About to execute: /nix/store/57zdzvsd1wcsfxbdrkpdz7hx35jb0ds9-unit-script-initrd-nixos-activation-start/bin/initrd-nixos-activation-start
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Forked /nix/store/57zdzvsd1wcsfxbdrkpdz7hx35jb0ds9-unit-script-initrd-nixos-activation-start/bin/initrd-nixos-activation-start as 495
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Changed dead -> start
Mar 22 09:37:43 localhost systemd[1]: Starting NixOS Activation...
Mar 22 09:37:43 localhost (on-start)[495]: Found cgroup2 on /sys/fs/cgroup/, full unified hierarchy
Mar 22 09:37:43 localhost (on-start)[495]: Found cgroup2 on /sys/fs/cgroup/, full unified hierarchy
Mar 22 09:37:43 localhost initrd-nixos-activation-start[495]: booting system configuration /nix/store/bnrs9syvy2gz7pmy1r5dd4jip672srhh-nixos-system-zebul-24.05.20240321.b0c93fc
Mar 22 09:37:43 localhost initrd-nixos-activation-start[495]: running activation script...
Mar 22 09:37:43 localhost initrd-nixos-activation-start[526]: chmod: changing permissions of '/bin': Read-only file system
Mar 22 09:37:43 localhost initrd-nixos-activation-start[527]: ln: failed to create symbolic link '/bin/.sh.tmp': Read-only file system
Mar 22 09:37:43 localhost initrd-nixos-activation-start[528]: mv: cannot stat '/bin/.sh.tmp': No such file or directory
Mar 22 09:37:43 localhost initrd-nixos-activation-start[524]: Activation script snippet 'binsh' failed (1)
Mar 22 09:37:43 localhost initrd-nixos-activation-start[531]: write_file '/var/lib/nixos/.tempqKJuf' - sysopen: Read-only file system at /nix/store/38hbyd1gwyszqslh3wycv5ly03dr75gj-update-users-groups.pl line 23.
Mar 22 09:37:43 localhost initrd-nixos-activation-start[524]: Activation script snippet 'users' failed (30)
Mar 22 09:37:43 localhost initrd-nixos-activation-start[524]: setting up /etc...
Mar 22 09:37:43 localhost initrd-nixos-activation-start[534]: Died at /nix/store/rg5rf512szdxmnj9qal3wfdnpfsx38qi-setup-etc.pl line 27.
Mar 22 09:37:43 localhost initrd-nixos-activation-start[524]: Activation script snippet 'etc' failed (30)
Mar 22 09:37:43 localhost initrd-nixos-activation-start[562]: chmod: changing permissions of '/usr/bin': Read-only file system
Mar 22 09:37:43 localhost initrd-nixos-activation-start[563]: ln: failed to create symbolic link '/usr/bin/.env.tmp': Read-only file system
Mar 22 09:37:43 localhost initrd-nixos-activation-start[564]: mv: cannot stat '/usr/bin/.env.tmp': No such file or directory
Mar 22 09:37:43 localhost initrd-nixos-activation-start[524]: Activation script snippet 'usrbinenv' failed (1)
Mar 22 09:37:43 localhost initrd-nixos-activation-start[495]: /nix/store/bnrs9syvy2gz7pmy1r5dd4jip672srhh-nixos-system-zebul-24.05.20240321.b0c93fc/prepare-root: line 133: /etc/machine-id: Read-only file system
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Child 495 belongs to initrd-nixos-activation.service.
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Main process exited, code=exited, status=0/SUCCESS (success)
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Deactivated successfully.
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Service will not restart (restart setting)
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Changed start -> dead
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Job 2 initrd-nixos-activation.service/start finished, result=done
Mar 22 09:37:43 localhost systemd[1]: Finished NixOS Activation.
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Consumed 119ms CPU time.
Mar 22 09:37:43 localhost systemd[1]: initrd-nixos-activation.service: Releasing resources...
Mar 22 09:37:48 zebul systemd[1]: initrd-nixos-activation.service: Collecting.

philiptaron added a commit to philiptaron/flock.nix that referenced this pull request Mar 25, 2024
… for the forseeable."

This reverts commit d3bb46c.
Per Matrix discussion, we're going to add in `rw` to the kernel arguments.
@philiptaron philiptaron mentioned this pull request Sep 3, 2024
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
9 participants