As seen in several other places (here and here for example), there’s a bit of an ordering, timing or even race condition like problem with trying to expose bind mounts for NFS (specifically NFSv4) when the underlying mount is coming from ZFS.
I’ve tried numerous incantations attempting to make use of the systemd based functionality of x-systemd.requires
as a mount option without any luck, trying to depend on various things like zfs-mount.service
or even my specific zfs-import-data.service
for the pool in question. I also tried various path based approaches like x-systemd.requires=/data
, all of which resulted in empty bind mount points under /srv/nfs.
Now, I am seeing at least the ordering of all of these things seemingly happening correctly:
Dec 31 00:24:27 arrakis systemd[1]: Finished Wait for udev To Complete Device Initialization.
Dec 31 00:24:27 arrakis systemd[1]: Starting Import ZFS pool "data"...
Dec 31 00:24:32 arrakis zfs-import-data-start[1591]: importing ZFS pool "data"...Successfully imported data
Dec 31 00:24:32 arrakis systemd[1]: Finished Import ZFS pool "data".
Dec 31 00:24:32 arrakis systemd[1]: Reached target ZFS pool import target.
Dec 31 00:24:32 arrakis systemd[1]: Mounting /srv/nfs/stuff...
Dec 31 00:24:32 arrakis systemd[1]: Mounting /srv/nfs/stuff2...
Dec 31 00:24:32 arrakis systemd[1]: Starting Mount ZFS filesystems...
Dec 31 00:24:32 arrakis systemd[1]: Mounted /srv/nfs/stuff.
Dec 31 00:24:32 arrakis systemd[1]: Mounted /srv/nfs/stuff2.
Dec 31 00:24:33 arrakis systemd[1]: Finished Mount ZFS filesystems.
Dec 31 00:24:33 arrakis systemd[1]: Reached target Local File Systems.
Empty directories are still the result, which is why I think this could be a timing/race type situation possibly. And I didn’t see any obvious way to inject any delay via the auto generated mount units via systemd-fstab-generator. Although, as it turns out, too much additional delay isn’t apparently necessary.
So for now, the working solution I’ve landed on is to define the file system bind mounts like this:
fileSystems."/srv/nfs/stuff" = {
device = "/data/stuff";
fsType = "none";
options = [
"bind"
"noauto"
];
};
and then use my own systemd service to manually do the mounts:
"nfs-bind-mount" = {
after = [ "zfs-import-data.service" ];
description = "Bind NFS exports to ZFS paths";
script = ''
${pkgs.util-linux}/bin/mount /srv/nfs/stuff
${pkgs.util-linux}/bin/mount /srv/nfs/stuff2
'';
wantedBy = [ "local-fs.target" ];
};
All of which gives me the desired result of having those bind mounts properly populated after boot finishes without me needing to manually mount them myself since no variation I attempted to make systemd handle this directly was successful.
I’m posting this partly to see if anyone else ever has gotten this working correctly through what seems like it should be the desired mechanism (systemd), but mostly just to document the problem, at least as it presents trying to use the systemd supplied mechanism. Maybe there is yet another better way to define this that doesn’t involve creating my own manual service?
Either way, maybe it will help someone else at least in the meantime.