Systemd (v237) can do quite odd things with /etc/fstab
bind mounts
Suppose, not entirely hypothetically, that you have an Ubuntu 18.04
system (which has systemd v237) and you want to add a bind mount for a ZFS filesystem; for example, you want to bind
mount /cs/mail
on to /var/mail
. You're managing ZFS filesystems
themselves through ZFS's usual boot time mechanisms
instead of /etc/fstab
, but putting the bind mount itself in
/etc/fstab
is the simplest and shortest way. So you put the
following in /etc/fstab
:
/cs/mail /var/mail none bind
If you boot the system and do a 'df /var/mail
', everything will
look good. But this is probably an illusion that will be exposed
if you do 'grep /var/mail /proc/mounts
', because you most likely
really have two bind mounts, one on top of the other:
/dev/sda1 /var/mail ext4 rw,relatime,errors=remount-ro,data=ordered 0 0 tank/cs/mail /var/mail zfs rw,nosuid,nodev,noatime,xattr,noacl 0 0
The ultimate cause of this is the same as it was in 2014, when I wrote
an entry on bind mounts with systemd and non-fstab
filesystems. Since there is no /etc/fstab
line or .mount
unit for /cs/mail
, systemd doesn't know that it's a separate
filesystem until ZFS's commands run and the filesystem magically
appears. So apparently systemd does the bind mount twice, once when just
the root filesystem is mounted (which looks like everything needed) and
then a second time when a /cs/mail
filesystem appears and it knows
more. If another program (such as your IMAP server) looks at /var/mail
before the second mount appears, it will see (and possibly take a
reference to) the bad, empty version on the root filesystem.
The automatically created systemd mount unit for /cs/mail
will
include a 'RequiresMountsFor=/var
/cs/mail
', but this doesn't mean that systemd will require a
/cs/mail
mount. When systemd starts, as far as it knows /cs/mail
only requires the root filesystem.
Suppose that you then decide to get clever and use brute force. If
systemd is bind mounting the root filesystem's empty /cs/mail
directory, let's give it a mount source that doesn't exist on the
root filesystem by changing fstab
to be:
/cs/mail/mail /var/mail none bind
Your ZFS filesystem remains /cs/mail
; you will just put everything
in a directory in it, /cs/mail/mail
. So you make this change,
reboot your system, and now you find that /cs/mail
is not mounted
as a ZFS filesystem, and you still have a bind mount from the root
filesystem. As far as I can tell, systemd v237 will automatically
mkdir
the source of a bind mount if it doesn't exist. So systemd
created a /cs/mail/mail
on the root filesystem and bind mounted it to
/var/mail
, and then ZFS found that its /cs/mail
mount point wasn't
empty and refused to mount the ZFS filesystem. My clever idea made me
worse off than before.
(This behavior doesn't seem to be documented in the current systemd.mountd(5) manual page, but systemd v237 does date from 2018. On the other hand, it's not documented in the v237 version of the manual page either.)
These days, systemd allows you to express some but not all systemd
unit conditions in /etc/fstab
(see [systemd.mountd(5)]]). However,
I still think that a real .mount
unit file is your most reliable
bet. This also lets you use 'ConditionPathExists
'
to check for the presence of some known file or subdirectory in
your original filesystem in a way that hopefully won't cause systemd
to create it on the root filesystem if it's missing.
(In a modern systemd you can also use ConditionPathIsMountPoint
,
but that's not in v237.)
PS: I haven't tested this on anything more recent than the Ubuntu 18.04 systemd, since Ubuntu 18.04 is what we're going to be using for the particular server where this is an issue (because it's what all our other ZFS fileservers use). That is also part of why this is not currently any sort of bug report to anyone. For that matter, I don't know if this is a bug, other than perhaps a documentation bug.
|
|