fileSystems vs systemd.mounts, and boot.tmp settings reuse

I’m thinking of creating a tmpfs folder under /home/tmp and I found it to be very simple:

fileSystems."/home/tmp".fsType = "tmpfs";

However, I wanted to inherit settings from config.boot.tmp to avoid repeating code. In looking for how to do this, I found that the module uses a completely different way to mount /tmp:

tmpfs nix code
systemd.mounts = lib.mkIf cfg.useTmpfs [
  {
    what = "tmpfs";
    where = "/tmp";
    type = "tmpfs";
    mountConfig.Options = lib.concatStringsSep "," [
      "mode=1777"
      "strictatime"
      "rw"
      "nosuid"
      "nodev"
      "size=${toString cfg.tmpfsSize}"
      "huge=${cfg.tmpfsHugeMemoryPages}"
    ];
  }
];

Now I wonder, what’s the practical difference? The implementation for fileSystems does seems somewhat long and monolithic, but in the end it creates systemd mount units like mnt-data.mount anyway.

I would of course prefer the fileSystems snippet, but I don’t know if there’s a good way to reuse options from /tmp with that. If I were to use systemd.mounts, then perhaps I can copy the entry in the list, replace the path, (/tmp to /home/tmp) and append it with the rest?

Some context for why I would want a /home/tmp; I like to use tmpfs extensively to avoid clutter and reduce disk IO, like for downloads that I’d unzip and throw away the zip file. However the global tmpfs in /tmp isn’t very nice for this because there’s a lot of system files and directories there that add clutter. Hence, /home/tmp, which also creates the interesting option of having a user named “tmp” with a completely temporary home directory for some minor tests.

fileSystems will be added to /etc/fstab, which is parsed by systemd on bootup to create the necessary transient mount units. systemd.mounts generates an actual mount unit and doesn’t write to /etc/fstab.

1 Like

fileSystems will be added to /etc/fstab, which is parsed by systemd on bootup to create the necessary transient mount units

I did notice that /tmp doesn’t show in /etc/fstab. However, even via the fileSystems option, /home/tmp was mounted for me on system activation, not just on bootup.

This doesn’t really tell me why to use one over the other though.

This is what I came up with, but it is of course infinite recursion…

systemd.mounts =
  let
    tmpMount = lib.findFirst (mount: mount.where == "/tmp") null config.systemd.mounts;
  in
  lib.mkIf (tmpMount != null) (
    builtins.mapAttrs (name: value: if name == "where" then "/home/tmp" else value) tmpMount
  );

This is what works for me, but it’s not exactly clean…

fileSystems."/home/tmp" = lib.mkDefault {
  fsType = "tmpfs";

  # inherit options created by boot.tmp.useTmpfs if avaliable
  options =
    let
      tmpMount = lib.findFirst (mount: mount.where == "/tmp") null config.systemd.mounts;
    in
    lib.mkIf (tmpMount != null) (lib.splitStringBy (p: c: c == ",") false tmpMount.mountConfig.Options);
};

As a user, there really isn’t a strong reason to prefer one over the other. Normally people just stick to /etc/fstab since its a little bit quicker to write mounts into, but on NixOS the process is pretty much identical thanks to the module system so that really doesn’t apply here. Creating a mount unit can be helpful if you have specific service dependencies that would otherwise be more difficult/impossible to declare in /etc/fstab (suppose you want to fire up a mount alongside some other service), though that’s also a niche case.

Personally, I’d say that if you don’t have a specific reason to want a systemd mount unit, just stick to fileSystems.

2 Likes