lol

Merge pull request #234877 from ElvishJerricco/auto-format-and-resize-with-systemd

Auto format and resize with systemd

authored by

Florian Klink and committed by
GitHub
4627ee74 5344f093

+47 -92
+4
nixos/doc/manual/release-notes/rl-2311.section.md
··· 28 29 - `util-linux` is now supported on Darwin and is no longer an alias to `unixtools`. Use the `unixtools.util-linux` package for access to the Apple variants of the utilities. 30 31 ## Other Notable Changes {#sec-release-23.11-notable-changes} 32 33 - The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.
··· 28 29 - `util-linux` is now supported on Darwin and is no longer an alias to `unixtools`. Use the `unixtools.util-linux` package for access to the Apple variants of the utilities. 30 31 + - `fileSystems.<name>.autoFormat` now uses `systemd-makefs`, which does not accept formatting options. Therefore, `fileSystems.<name>.formatOptions` has been removed. 32 + 33 + - `fileSystems.<name>.autoResize` now uses `systemd-growfs` to resize the file system online in stage 2. This means that `f2fs` and `ext2` can no longer be auto resized, while `xfs` and `btrfs` now can be. 34 + 35 ## Other Notable Changes {#sec-release-23.11-notable-changes} 36 37 - The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.
-16
nixos/modules/system/boot/stage-1-init.sh
··· 374 375 checkFS "$device" "$fsType" 376 377 - # Optionally resize the filesystem. 378 - case $options in 379 - *x-nixos.autoresize*) 380 - if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then 381 - modprobe "$fsType" 382 - echo "resizing $device..." 383 - e2fsck -fp "$device" 384 - resize2fs "$device" 385 - elif [ "$fsType" = f2fs ]; then 386 - echo "resizing $device..." 387 - fsck.f2fs -fp "$device" 388 - resize.f2fs "$device" 389 - fi 390 - ;; 391 - esac 392 - 393 # Create backing directories for overlayfs 394 if [ "$fsType" = overlay ]; then 395 for i in upper work; do
··· 374 375 checkFS "$device" "$fsType" 376 377 # Create backing directories for overlayfs 378 if [ "$fsType" = overlay ]; then 379 for i in upper work; do
-6
nixos/modules/system/boot/stage-1.nix
··· 150 copy_bin_and_libs ${pkgs.kmod}/bin/kmod 151 ln -sf kmod $out/bin/modprobe 152 153 - # Copy resize2fs if any ext* filesystems are to be resized 154 - ${optionalString (any (fs: fs.autoResize && (lib.hasPrefix "ext" fs.fsType)) fileSystems) '' 155 - # We need mke2fs in the initrd. 156 - copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs 157 - ''} 158 - 159 # Copy multipath. 160 ${optionalString config.services.multipath.enable '' 161 copy_bin_and_libs ${config.services.multipath.package}/bin/multipath
··· 150 copy_bin_and_libs ${pkgs.kmod}/bin/kmod 151 ln -sf kmod $out/bin/modprobe 152 153 # Copy multipath. 154 ${optionalString config.services.multipath.enable '' 155 copy_bin_and_libs ${config.services.multipath.package}/bin/multipath
+9
nixos/modules/system/boot/systemd.nix
··· 588 systemd.services."systemd-backlight@".restartIfChanged = false; 589 systemd.services."systemd-fsck@".restartIfChanged = false; 590 systemd.services."systemd-fsck@".path = [ config.system.path ]; 591 systemd.services.systemd-random-seed.restartIfChanged = false; 592 systemd.services.systemd-remount-fs.restartIfChanged = false; 593 systemd.services.systemd-update-utmp.restartIfChanged = false;
··· 588 systemd.services."systemd-backlight@".restartIfChanged = false; 589 systemd.services."systemd-fsck@".restartIfChanged = false; 590 systemd.services."systemd-fsck@".path = [ config.system.path ]; 591 + systemd.services."systemd-makefs@" = { 592 + restartIfChanged = false; 593 + path = [ pkgs.util-linux ] ++ config.system.fsPackages; 594 + # Since there is no /etc/systemd/system/systemd-makefs@.service 595 + # file, the units generated in /run/systemd/generator would 596 + # override anything we put here. But by forcing the use of a 597 + # drop-in in /etc, it does apply. 598 + overrideStrategy = "asDropin"; 599 + }; 600 systemd.services.systemd-random-seed.restartIfChanged = false; 601 systemd.services.systemd-remount-fs.restartIfChanged = false; 602 systemd.services.systemd-update-utmp.restartIfChanged = false;
-3
nixos/modules/system/boot/systemd/initrd.nix
··· 56 "systemd-ask-password-console.path" 57 "systemd-ask-password-console.service" 58 "systemd-fsck@.service" 59 - "systemd-growfs@.service" 60 "systemd-halt.service" 61 "systemd-hibernate-resume@.service" 62 "systemd-journald-audit.socket" ··· 93 fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; 94 95 needMakefs = lib.any (fs: fs.autoFormat) fileSystems; 96 - needGrowfs = lib.any (fs: fs.autoResize) fileSystems; 97 98 kernel-name = config.boot.kernelPackages.kernel.name or "kernel"; 99 modulesTree = config.system.modulesTree.override { name = kernel-name + "-modules"; }; ··· 400 storePaths = [ 401 # systemd tooling 402 "${cfg.package}/lib/systemd/systemd-fsck" 403 - (lib.mkIf needGrowfs "${cfg.package}/lib/systemd/systemd-growfs") 404 "${cfg.package}/lib/systemd/systemd-hibernate-resume" 405 "${cfg.package}/lib/systemd/systemd-journald" 406 (lib.mkIf needMakefs "${cfg.package}/lib/systemd/systemd-makefs")
··· 56 "systemd-ask-password-console.path" 57 "systemd-ask-password-console.service" 58 "systemd-fsck@.service" 59 "systemd-halt.service" 60 "systemd-hibernate-resume@.service" 61 "systemd-journald-audit.socket" ··· 92 fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; 93 94 needMakefs = lib.any (fs: fs.autoFormat) fileSystems; 95 96 kernel-name = config.boot.kernelPackages.kernel.name or "kernel"; 97 modulesTree = config.system.modulesTree.override { name = kernel-name + "-modules"; }; ··· 398 storePaths = [ 399 # systemd tooling 400 "${cfg.package}/lib/systemd/systemd-fsck" 401 "${cfg.package}/lib/systemd/systemd-hibernate-resume" 402 "${cfg.package}/lib/systemd/systemd-journald" 403 (lib.mkIf needMakefs "${cfg.package}/lib/systemd/systemd-makefs")
+33 -61
nixos/modules/tasks/filesystems.nix
··· 112 }; 113 114 formatOptions = mkOption { 115 - default = ""; 116 - type = types.str; 117 - description = lib.mdDoc '' 118 - If {option}`autoFormat` option is set specifies 119 - extra options passed to mkfs. 120 - ''; 121 }; 122 123 autoResize = mkOption { ··· 139 140 }; 141 142 - config = let 143 - defaultFormatOptions = 144 - # -F needed to allow bare block device without partitions 145 - if (builtins.substring 0 3 config.fsType) == "ext" then "-F" 146 - # -q needed for non-interactive operations 147 - else if config.fsType == "jfs" then "-q" 148 - # (same here) 149 - else if config.fsType == "reiserfs" then "-q" 150 - else null; 151 - in { 152 - options = mkMerge [ 153 - (mkIf config.autoResize [ "x-nixos.autoresize" ]) 154 - (mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ]) 155 - ]; 156 - formatOptions = mkIf (defaultFormatOptions != null) (mkDefault defaultFormatOptions); 157 - }; 158 159 }; 160 ··· 201 skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck || isBindMount fs; 202 # https://wiki.archlinux.org/index.php/fstab#Filepath_spaces 203 escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string; 204 - in fstabFileSystems: { rootPrefix ? "", extraOpts ? (fs: []) }: concatMapStrings (fs: 205 (optionalString (isBindMount fs) (escape rootPrefix)) 206 + (if fs.device != null then escape fs.device 207 else if fs.label != null then "/dev/disk/by-label/${escape fs.label}" 208 else throw "No device specified for mount point ‘${fs.mountPoint}’.") 209 + " " + escape fs.mountPoint 210 + " " + fs.fsType 211 - + " " + escape (builtins.concatStringsSep "," (fs.options ++ (extraOpts fs))) 212 + " 0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2") 213 + "\n" 214 ) fstabFileSystems; 215 216 initrdFstab = pkgs.writeText "initrd-fstab" (makeFstabEntries (filter utils.fsNeededForBoot fileSystems) { 217 rootPrefix = "/sysroot"; 218 - extraOpts = fs: 219 - (optional fs.autoResize "x-systemd.growfs") 220 - ++ (optional fs.autoFormat "x-systemd.makefs"); 221 }); 222 223 in ··· 319 320 assertions = let 321 ls = sep: concatMapStringsSep sep (x: x.mountPoint); 322 - notAutoResizable = fs: fs.autoResize && !(hasPrefix "ext" fs.fsType || fs.fsType == "f2fs"); 323 in [ 324 { assertion = ! (fileSystems' ? cycle); 325 message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}"; ··· 327 { assertion = ! (any notAutoResizable fileSystems); 328 message = let 329 fs = head (filter notAutoResizable fileSystems); 330 - in 331 - "Mountpoint '${fs.mountPoint}': 'autoResize = true' is not supported for 'fsType = \"${fs.fsType}\"':${optionalString (fs.fsType == "auto") " fsType has to be explicitly set and"} only the ext filesystems and f2fs support it."; 332 } 333 ]; 334 ··· 377 wants = [ "local-fs.target" "remote-fs.target" ]; 378 }; 379 380 - systemd.services = 381 - 382 - # Emit systemd services to format requested filesystems. 383 - let 384 - formatDevice = fs: 385 - let 386 - mountPoint' = "${escapeSystemdPath fs.mountPoint}.mount"; 387 - device' = escapeSystemdPath fs.device; 388 - device'' = "${device'}.device"; 389 - in nameValuePair "mkfs-${device'}" 390 - { description = "Initialisation of Filesystem ${fs.device}"; 391 - wantedBy = [ mountPoint' ]; 392 - before = [ mountPoint' "systemd-fsck@${device'}.service" ]; 393 - requires = [ device'' ]; 394 - after = [ device'' ]; 395 - path = [ pkgs.util-linux ] ++ config.system.fsPackages; 396 - script = 397 - '' 398 - if ! [ -e "${fs.device}" ]; then exit 1; fi 399 - # FIXME: this is scary. The test could be more robust. 400 - type=$(blkid -p -s TYPE -o value "${fs.device}" || true) 401 - if [ -z "$type" ]; then 402 - echo "creating ${fs.fsType} filesystem on ${fs.device}..." 403 - mkfs.${fs.fsType} ${fs.formatOptions} "${fs.device}" 404 - fi 405 - ''; 406 - unitConfig.RequiresMountsFor = [ "${dirOf fs.device}" ]; 407 - unitConfig.DefaultDependencies = false; # needed to prevent a cycle 408 - serviceConfig.Type = "oneshot"; 409 - }; 410 - in listToAttrs (map formatDevice (filter (fs: fs.autoFormat && !(utils.fsNeededForBoot fs)) fileSystems)) // { 411 # Mount /sys/fs/pstore for evacuating panic logs and crashdumps from persistent storage onto the disk using systemd-pstore. 412 # This cannot be done with the other special filesystems because the pstore module (which creates the mount point) is not loaded then. 413 "mount-pstore" = {
··· 112 }; 113 114 formatOptions = mkOption { 115 + visible = false; 116 + type = types.unspecified; 117 + default = null; 118 }; 119 120 autoResize = mkOption { ··· 136 137 }; 138 139 + config.options = mkMerge [ 140 + (mkIf config.autoResize [ "x-systemd.growfs" ]) 141 + (mkIf config.autoFormat [ "x-systemd.makefs" ]) 142 + (mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ]) 143 + ]; 144 145 }; 146 ··· 187 skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck || isBindMount fs; 188 # https://wiki.archlinux.org/index.php/fstab#Filepath_spaces 189 escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string; 190 + in fstabFileSystems: { rootPrefix ? "" }: concatMapStrings (fs: 191 (optionalString (isBindMount fs) (escape rootPrefix)) 192 + (if fs.device != null then escape fs.device 193 else if fs.label != null then "/dev/disk/by-label/${escape fs.label}" 194 else throw "No device specified for mount point ‘${fs.mountPoint}’.") 195 + " " + escape fs.mountPoint 196 + " " + fs.fsType 197 + + " " + escape (builtins.concatStringsSep "," fs.options) 198 + " 0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2") 199 + "\n" 200 ) fstabFileSystems; 201 202 initrdFstab = pkgs.writeText "initrd-fstab" (makeFstabEntries (filter utils.fsNeededForBoot fileSystems) { 203 rootPrefix = "/sysroot"; 204 }); 205 206 in ··· 302 303 assertions = let 304 ls = sep: concatMapStringsSep sep (x: x.mountPoint); 305 + resizableFSes = [ 306 + "ext3" 307 + "ext4" 308 + "btrfs" 309 + "xfs" 310 + ]; 311 + notAutoResizable = fs: fs.autoResize && !(builtins.elem fs.fsType resizableFSes); 312 in [ 313 { assertion = ! (fileSystems' ? cycle); 314 message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}"; ··· 316 { assertion = ! (any notAutoResizable fileSystems); 317 message = let 318 fs = head (filter notAutoResizable fileSystems); 319 + in '' 320 + Mountpoint '${fs.mountPoint}': 'autoResize = true' is not supported for 'fsType = "${fs.fsType}"' 321 + ${optionalString (fs.fsType == "auto") "fsType has to be explicitly set and"} 322 + only the following support it: ${lib.concatStringsSep ", " resizableFSes}. 323 + ''; 324 + } 325 + { 326 + assertion = ! (any (fs: fs.formatOptions != null) fileSystems); 327 + message = let 328 + fs = head (filter (fs: fs.formatOptions != null) fileSystems); 329 + in '' 330 + 'fileSystems.<name>.formatOptions' has been removed, since 331 + systemd-makefs does not support any way to provide formatting 332 + options. 333 + ''; 334 } 335 ]; 336 ··· 379 wants = [ "local-fs.target" "remote-fs.target" ]; 380 }; 381 382 + systemd.services = { 383 # Mount /sys/fs/pstore for evacuating panic logs and crashdumps from persistent storage onto the disk using systemd-pstore. 384 # This cannot be done with the other special filesystems because the pstore module (which creates the mount point) is not loaded then. 385 "mount-pstore" = {
-5
nixos/modules/tasks/filesystems/f2fs.nix
··· 15 16 boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) '' 17 copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/fsck.f2fs 18 - ${optionalString (any (fs: fs.autoResize) fileSystems) '' 19 - # We need f2fs-tools' tools to resize filesystems 20 - copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/resize.f2fs 21 - ''} 22 - 23 ''; 24 }; 25 }
··· 15 16 boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) '' 17 copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/fsck.f2fs 18 ''; 19 }; 20 }
+1 -1
nixos/tests/fsck.nix
··· 30 else "fsck.ext4.*/dev/vda"}'") 31 32 with subtest("mnt fs is fsckd"): 33 - machine.succeed("journalctl -b | grep 'fsck.*/dev/vdb.*clean'") 34 machine.succeed( 35 "grep 'Requires=systemd-fsck@dev-vdb.service' /run/systemd/generator/mnt.mount" 36 )
··· 30 else "fsck.ext4.*/dev/vda"}'") 31 32 with subtest("mnt fs is fsckd"): 33 + machine.succeed("journalctl -b | grep 'fsck.*vdb.*clean'") 34 machine.succeed( 35 "grep 'Requires=systemd-fsck@dev-vdb.service' /run/systemd/generator/mnt.mount" 36 )