Systemd Udev – Mount fuse.mergerfs in Udev Script

systemdudevunionfs

I use a udev rule to recognize when a specific USB stick is plugged. When it's plugged in, a bash script is started which mounts some devices. That works very well after I did some changes to the systemd-udev service as described here.

However, one of the mounts fail. It is a fuse-mergerfs mount. The command itself seems to succeed, but when doing an ls on the mount folder I get a strange output and I cannot access the folder:

d?????????  ? ?    ?       ?            ? mountpoint

But if I run the mount command manually from the terminal everything is fine.

It also doesn't matter if the stick is plugged in during boot or if I plug it in after the system has already started. Mounting the fuse-mergerfs device does not work when mount is called by the udev script.

Do you have any ideas?

Best Answer

[Using RUN in udev rules] is only suitable for short-lived scripts, as they will be killed if they are stil running after a timeout period.

I.e. the FUSE background process that implements your filesystem gets killed.

One alternative that comes to mind: if you have the systemd-mount command, you could try using that in place of your mount command. It will create a transient .mount unit (as opposed to a .service unit), and run the mount program inside that unit.

The source I am quoting tries to provide a more general solution for long-running processes:

https://yakking.branchable.com/posts/systemd-2-udevd/

If you need a longer-running service, then you should integrate it with a systemd unit, by defining the unit like:

cat >/etc/systemd/system/my-service@.service <<'EOF'
[Unit]
Description=My Service
[Service]
Type=simple
ExecStart=/path/to/your/script %I
EOF

And add ENV{SYSTEMD_WANTS}="my-service@%k.service" to the udev rule.

This will run /path/to/your/script and pass it the path to the device that has just appeared.

Unfortunately the above instructions are not correct for your case.

Your problem is not that your script itself took too long before returning. The problem is that your script returns after starting a "background process"; the process that implements your FUSE filesystem. When the script finishes, systemd thinks it needs to clean up, and kill all the left-over processes which were started by the script.

This case is very similar to a legacy sysvinit script. So we can use the same solution they do:

When you write a systemd service to mount a FUSE filesystem, do not use Type=simple or Type=oneshot. Use Type=forking instead.

Related Question