Merge pull request #234877 from ElvishJerricco/auto-format-and-resize-with-systemd
Auto format and resize with systemd
This commit is contained in:
commit
4627ee741d
8 changed files with 47 additions and 92 deletions
|
@ -28,6 +28,10 @@
|
|||
|
||||
- `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.
|
||||
|
||||
- `fileSystems.<name>.autoFormat` now uses `systemd-makefs`, which does not accept formatting options. Therefore, `fileSystems.<name>.formatOptions` has been removed.
|
||||
|
||||
- `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.
|
||||
|
||||
## Other Notable Changes {#sec-release-23.11-notable-changes}
|
||||
|
||||
- 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.
|
||||
|
|
|
@ -374,22 +374,6 @@ mountFS() {
|
|||
|
||||
checkFS "$device" "$fsType"
|
||||
|
||||
# Optionally resize the filesystem.
|
||||
case $options in
|
||||
*x-nixos.autoresize*)
|
||||
if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then
|
||||
modprobe "$fsType"
|
||||
echo "resizing $device..."
|
||||
e2fsck -fp "$device"
|
||||
resize2fs "$device"
|
||||
elif [ "$fsType" = f2fs ]; then
|
||||
echo "resizing $device..."
|
||||
fsck.f2fs -fp "$device"
|
||||
resize.f2fs "$device"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create backing directories for overlayfs
|
||||
if [ "$fsType" = overlay ]; then
|
||||
for i in upper work; do
|
||||
|
|
|
@ -150,12 +150,6 @@ let
|
|||
copy_bin_and_libs ${pkgs.kmod}/bin/kmod
|
||||
ln -sf kmod $out/bin/modprobe
|
||||
|
||||
# Copy resize2fs if any ext* filesystems are to be resized
|
||||
${optionalString (any (fs: fs.autoResize && (lib.hasPrefix "ext" fs.fsType)) fileSystems) ''
|
||||
# We need mke2fs in the initrd.
|
||||
copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs
|
||||
''}
|
||||
|
||||
# Copy multipath.
|
||||
${optionalString config.services.multipath.enable ''
|
||||
copy_bin_and_libs ${config.services.multipath.package}/bin/multipath
|
||||
|
|
|
@ -588,6 +588,15 @@ in
|
|||
systemd.services."systemd-backlight@".restartIfChanged = false;
|
||||
systemd.services."systemd-fsck@".restartIfChanged = false;
|
||||
systemd.services."systemd-fsck@".path = [ config.system.path ];
|
||||
systemd.services."systemd-makefs@" = {
|
||||
restartIfChanged = false;
|
||||
path = [ pkgs.util-linux ] ++ config.system.fsPackages;
|
||||
# Since there is no /etc/systemd/system/systemd-makefs@.service
|
||||
# file, the units generated in /run/systemd/generator would
|
||||
# override anything we put here. But by forcing the use of a
|
||||
# drop-in in /etc, it does apply.
|
||||
overrideStrategy = "asDropin";
|
||||
};
|
||||
systemd.services.systemd-random-seed.restartIfChanged = false;
|
||||
systemd.services.systemd-remount-fs.restartIfChanged = false;
|
||||
systemd.services.systemd-update-utmp.restartIfChanged = false;
|
||||
|
|
|
@ -56,7 +56,6 @@ let
|
|||
"systemd-ask-password-console.path"
|
||||
"systemd-ask-password-console.service"
|
||||
"systemd-fsck@.service"
|
||||
"systemd-growfs@.service"
|
||||
"systemd-halt.service"
|
||||
"systemd-hibernate-resume@.service"
|
||||
"systemd-journald-audit.socket"
|
||||
|
@ -93,7 +92,6 @@ let
|
|||
fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems;
|
||||
|
||||
needMakefs = lib.any (fs: fs.autoFormat) fileSystems;
|
||||
needGrowfs = lib.any (fs: fs.autoResize) fileSystems;
|
||||
|
||||
kernel-name = config.boot.kernelPackages.kernel.name or "kernel";
|
||||
modulesTree = config.system.modulesTree.override { name = kernel-name + "-modules"; };
|
||||
|
@ -400,7 +398,6 @@ in {
|
|||
storePaths = [
|
||||
# systemd tooling
|
||||
"${cfg.package}/lib/systemd/systemd-fsck"
|
||||
(lib.mkIf needGrowfs "${cfg.package}/lib/systemd/systemd-growfs")
|
||||
"${cfg.package}/lib/systemd/systemd-hibernate-resume"
|
||||
"${cfg.package}/lib/systemd/systemd-journald"
|
||||
(lib.mkIf needMakefs "${cfg.package}/lib/systemd/systemd-makefs")
|
||||
|
|
|
@ -112,12 +112,9 @@ let
|
|||
};
|
||||
|
||||
formatOptions = mkOption {
|
||||
default = "";
|
||||
type = types.str;
|
||||
description = lib.mdDoc ''
|
||||
If {option}`autoFormat` option is set specifies
|
||||
extra options passed to mkfs.
|
||||
'';
|
||||
visible = false;
|
||||
type = types.unspecified;
|
||||
default = null;
|
||||
};
|
||||
|
||||
autoResize = mkOption {
|
||||
|
@ -139,22 +136,11 @@ let
|
|||
|
||||
};
|
||||
|
||||
config = let
|
||||
defaultFormatOptions =
|
||||
# -F needed to allow bare block device without partitions
|
||||
if (builtins.substring 0 3 config.fsType) == "ext" then "-F"
|
||||
# -q needed for non-interactive operations
|
||||
else if config.fsType == "jfs" then "-q"
|
||||
# (same here)
|
||||
else if config.fsType == "reiserfs" then "-q"
|
||||
else null;
|
||||
in {
|
||||
options = mkMerge [
|
||||
(mkIf config.autoResize [ "x-nixos.autoresize" ])
|
||||
(mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ])
|
||||
];
|
||||
formatOptions = mkIf (defaultFormatOptions != null) (mkDefault defaultFormatOptions);
|
||||
};
|
||||
config.options = mkMerge [
|
||||
(mkIf config.autoResize [ "x-systemd.growfs" ])
|
||||
(mkIf config.autoFormat [ "x-systemd.makefs" ])
|
||||
(mkIf (utils.fsNeededForBoot config) [ "x-initrd.mount" ])
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
|
@ -201,23 +187,20 @@ let
|
|||
skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck || isBindMount fs;
|
||||
# https://wiki.archlinux.org/index.php/fstab#Filepath_spaces
|
||||
escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string;
|
||||
in fstabFileSystems: { rootPrefix ? "", extraOpts ? (fs: []) }: concatMapStrings (fs:
|
||||
in fstabFileSystems: { rootPrefix ? "" }: concatMapStrings (fs:
|
||||
(optionalString (isBindMount fs) (escape rootPrefix))
|
||||
+ (if fs.device != null then escape fs.device
|
||||
else if fs.label != null then "/dev/disk/by-label/${escape fs.label}"
|
||||
else throw "No device specified for mount point ‘${fs.mountPoint}’.")
|
||||
+ " " + escape fs.mountPoint
|
||||
+ " " + fs.fsType
|
||||
+ " " + escape (builtins.concatStringsSep "," (fs.options ++ (extraOpts fs)))
|
||||
+ " " + escape (builtins.concatStringsSep "," fs.options)
|
||||
+ " 0 " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2")
|
||||
+ "\n"
|
||||
) fstabFileSystems;
|
||||
|
||||
initrdFstab = pkgs.writeText "initrd-fstab" (makeFstabEntries (filter utils.fsNeededForBoot fileSystems) {
|
||||
rootPrefix = "/sysroot";
|
||||
extraOpts = fs:
|
||||
(optional fs.autoResize "x-systemd.growfs")
|
||||
++ (optional fs.autoFormat "x-systemd.makefs");
|
||||
});
|
||||
|
||||
in
|
||||
|
@ -319,7 +302,13 @@ in
|
|||
|
||||
assertions = let
|
||||
ls = sep: concatMapStringsSep sep (x: x.mountPoint);
|
||||
notAutoResizable = fs: fs.autoResize && !(hasPrefix "ext" fs.fsType || fs.fsType == "f2fs");
|
||||
resizableFSes = [
|
||||
"ext3"
|
||||
"ext4"
|
||||
"btrfs"
|
||||
"xfs"
|
||||
];
|
||||
notAutoResizable = fs: fs.autoResize && !(builtins.elem fs.fsType resizableFSes);
|
||||
in [
|
||||
{ assertion = ! (fileSystems' ? cycle);
|
||||
message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
|
||||
|
@ -327,8 +316,21 @@ in
|
|||
{ assertion = ! (any notAutoResizable fileSystems);
|
||||
message = let
|
||||
fs = head (filter notAutoResizable fileSystems);
|
||||
in
|
||||
"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.";
|
||||
in ''
|
||||
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 following support it: ${lib.concatStringsSep ", " resizableFSes}.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = ! (any (fs: fs.formatOptions != null) fileSystems);
|
||||
message = let
|
||||
fs = head (filter (fs: fs.formatOptions != null) fileSystems);
|
||||
in ''
|
||||
'fileSystems.<name>.formatOptions' has been removed, since
|
||||
systemd-makefs does not support any way to provide formatting
|
||||
options.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -377,37 +379,7 @@ in
|
|||
wants = [ "local-fs.target" "remote-fs.target" ];
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
|
||||
# Emit systemd services to format requested filesystems.
|
||||
let
|
||||
formatDevice = fs:
|
||||
let
|
||||
mountPoint' = "${escapeSystemdPath fs.mountPoint}.mount";
|
||||
device' = escapeSystemdPath fs.device;
|
||||
device'' = "${device'}.device";
|
||||
in nameValuePair "mkfs-${device'}"
|
||||
{ description = "Initialisation of Filesystem ${fs.device}";
|
||||
wantedBy = [ mountPoint' ];
|
||||
before = [ mountPoint' "systemd-fsck@${device'}.service" ];
|
||||
requires = [ device'' ];
|
||||
after = [ device'' ];
|
||||
path = [ pkgs.util-linux ] ++ config.system.fsPackages;
|
||||
script =
|
||||
''
|
||||
if ! [ -e "${fs.device}" ]; then exit 1; fi
|
||||
# FIXME: this is scary. The test could be more robust.
|
||||
type=$(blkid -p -s TYPE -o value "${fs.device}" || true)
|
||||
if [ -z "$type" ]; then
|
||||
echo "creating ${fs.fsType} filesystem on ${fs.device}..."
|
||||
mkfs.${fs.fsType} ${fs.formatOptions} "${fs.device}"
|
||||
fi
|
||||
'';
|
||||
unitConfig.RequiresMountsFor = [ "${dirOf fs.device}" ];
|
||||
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
in listToAttrs (map formatDevice (filter (fs: fs.autoFormat && !(utils.fsNeededForBoot fs)) fileSystems)) // {
|
||||
systemd.services = {
|
||||
# Mount /sys/fs/pstore for evacuating panic logs and crashdumps from persistent storage onto the disk using systemd-pstore.
|
||||
# This cannot be done with the other special filesystems because the pstore module (which creates the mount point) is not loaded then.
|
||||
"mount-pstore" = {
|
||||
|
|
|
@ -15,11 +15,6 @@ in
|
|||
|
||||
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
|
||||
copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/fsck.f2fs
|
||||
${optionalString (any (fs: fs.autoResize) fileSystems) ''
|
||||
# We need f2fs-tools' tools to resize filesystems
|
||||
copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/resize.f2fs
|
||||
''}
|
||||
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import ./make-test-python.nix {
|
|||
else "fsck.ext4.*/dev/vda"}'")
|
||||
|
||||
with subtest("mnt fs is fsckd"):
|
||||
machine.succeed("journalctl -b | grep 'fsck.*/dev/vdb.*clean'")
|
||||
machine.succeed("journalctl -b | grep 'fsck.*vdb.*clean'")
|
||||
machine.succeed(
|
||||
"grep 'Requires=systemd-fsck@dev-vdb.service' /run/systemd/generator/mnt.mount"
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue