NFS Mounts Fail at Boot

reading time ( words)

Recently I encountered a problem with mounting NFS filesystems at boot. In my case – and that of a few people who have asked related questions at various fora – the issue had to do with boot dependencies and race conditions. In this post I am explaining my issue and how I resolved it.

I first found this issue when rebuilding my local development environment, including a few VirtualBox machines that I use for testing various things. I tend to use VMs with a Host-only Adapter as well as additional network interfaces depending on what I need to accomplish.

New VMs would throw an error like this at boot:

[FAILED] Failed to mount /home/lem/go.
See 'systemctl status home-lem-go.mount' for details.
[DEPEND] Dependency failed for Remote File Systems.

And of course, my shared Go directory would not be mounted on the VM. After boot, A simple mount -a would mount the go filesystem with no issues, which was both puzzling and annoying at first. System logs would include lines such as this:

Jun  9 02:16:42 base mount[462]: mount.nfs: Network is unreachable

Turns out that these log entries would prove to be a great clue on what was going on behind the scenes.

The relationship between systemd and /etc/fstab

The introduction of systemd has brought many changes in the way Linux systems work. This is one of those areas.

Nowadays, systemd-fstab-generator automatically parses lines in the /etc/fstab file and generates equivalent systemd.mount stanzas that allow systemd to mount filesystems in order. This generally works well for filesystems that reside in local storage, fully available by the time the mount invocation comes. Remote filesystems are a slightly different story though.

The systemctl tool is useful to let us peek in the reasons behind the specific ordering of tasks at boot. In this case, we can see what would be required for the remote-fs.target to be satisfied:

systemctl list-dependencies --after remote-fs.target
remote-fs.target
  ├─home-lem-go.mount
  └─remote-fs-pre.target
    ├─rpcbind.service
    └─nfs-client.target
      ├─gssproxy.service
      ├─rpc-gssd.service
      └─rpc-svcgssd.service

So, in order to finish with target remote-fs.target, I would need to complete task home-lem-go.mount. And what about this one, derived from the corresponding line in /etc/fstab?

systemctl list-dependencies --after home-lem-go.mount
home-lem-go.mount
  ├─-.mount
  ├─system.slice
  ├─systemd-journald.socket
  ├─network-online.target
  │ ├─networking.service
  │ ├─systemd-networkd-wait-online.service
  │ └─network.target
  │   ├─ifupdown-pre.service
  │   ├─networking.service
  │   ├─systemd-networkd.service
  │   ├─wpa_supplicant.service
  │   └─network-pre.target
  ├─network.target
  │ ├─ifupdown-pre.service
  │ ├─networking.service
  │ ├─systemd-networkd.service
  │ ├─wpa_supplicant.service
  │ └─network-pre.target
  └─remote-fs-pre.target
    ├─rpcbind.service
    └─nfs-client.target
      ├─gssproxy.service
      ├─rpc-gssd.service
      └─rpc-svcgssd.service

It seems that systemd knows to get the network configured prior to mounting this remote filesystem. Or does it?

After going through RedHat’s Bugzilla #1027114 dating back to 2014 and poking a bit on my VMs, turns out that on the current Debian distribution, none of the network-related targets actually wait for DHCP configuration to complete when using if-up style configuration. In practical terms, this means that network-online.target is reported as complete as soon as the DHCP client is launched but not necessarily after the interface is actually usable.

By the time systemd gets to execute the required mount calls, the incomplete network configuration caused the Network is unreachable messages in my logs and the failure to mount the required filesystems.

My local solution

Some suggestions found through relevant use of Google-fu include switching to automount to have the filesystems mounted on demand, or using network-manager. I think these suggestions are sidestepping the issue.

I opted for a simpler alternative. Since the interface configuration in my VMs is quite simple, I just moved away the /etc/network/interfaces file and asked systemd to take care of my interfaces via .network files. Below is a trivial /etc/systemd/network/enp0s3.network that configures my first network interface:

[Match]
Name=enp0s3

[Network]
DHCP=ipv4

When network interface configuration is left to systemd, it knows when the DHCP configuration process is complete and forces the mounting of remote filesystems to wait for the network to be actually usable. More interesting setups are possible. Check the Debian Wiki on SystemdNetworkd for more information on how to address more complex network setups.