It turns out that systemd-automount behaves differently from autofs daemon and it does not return ENOENT when calling openat(pathref_dir_fd, "automount directory not yet mounted", ..), it returns a real fd without triggering the mount so the workaround implemented in ac7a16f9cc4bd97ef546d1b7b02605991000d0f9 does not work. To make it work we would need to check fstatfs() .f_type on each directory open if the fd is a pathref, but this approach seems sub-optimal (test patch https://gitlab.com/samba-team/devel/samba/-/commit/32f2f3c020060e48a53aa7d2ea7051e267e504d4). A possible mitigation could be to add a new per-share option to perform fstatfs() .f_type check only if enabled. Or discuss with systemd developers the possibility to return ENOENT as autofs does... Other ideas?
After further analysis this is not a systemd vs autofs behavior but direct automounts problem, either with autofs or systemd. Autofs indirect: # grep -v '^#' /etc/auto.master +auto.master /indirect/data /etc/auto.indirect # grep -v '^#' /etc/auto.indirect d1 localhost:/export/data/d1 d2 localhost:/export/data/d2 With browse_mode = no: # ls /indirect/ data # ls /indirect/data (empty) # ./test /indirect Target is /indirect chddir(/indirect) -> 0 openat(AT_FDCWD, data, O_RDONLY | O_NOFOLLOW | O_PATH) -> 3 openat(3, d1, O_RDONLY | O_NOFOLLOW | O_PATH) -> 4 <- [1] openat(AT_FDCWD, /proc/self/fd/4, O_RDONLY | O_DIRECTORY) -> 5 [1] This call triggers the mount as 'd1' does not exist With browse_mode = yes: # ls /indirect data # ls /indirect/data d1 d2 # ./test /indirect Target is /indirect chddir(/indirect) -> 0 openat(AT_FDCWD, data, O_RDONLY | O_NOFOLLOW | O_PATH) -> 3 openat(3, d1, O_RDONLY | O_NOFOLLOW | O_PATH) -> 4 openat(AT_FDCWD, /proc/self/fd/4, O_RDONLY | O_DIRECTORY) -> -1 Press key to continue (pid=19202)... While pid 19202 waits... # ls -l /proc/19202/fd/4/ ls: cannot open directory '/proc/19202/fd/4/': No such file or directory <- [2] # ls -l /proc/19202/fd/4 l--------- 1 root root 64 feb 13 12:29 /proc/19202/fd/4 -> /indirect/data/d1 [2] Why???? Now, autofs direct automounts: # grep -v "^#" /etc/auto.master +auto.master /- /etc/auto.direct # grep -v "^#" /etc/auto.direct /direct/data/d1 localhost:/export/data/d1 /direct/data/d2 localhost:/export/data/d2 # ls /direct/ data # ls /direct/data/ d1 d2 # ./test /direct Target is /direct chddir(/direct) -> 0 openat(AT_FDCWD, data, O_RDONLY | O_NOFOLLOW | O_PATH) -> 3 openat(3, d1, O_RDONLY | O_NOFOLLOW | O_PATH) -> 4 openat(AT_FDCWD, /proc/self/fd/4, O_RDONLY | O_DIRECTORY) -> 5 <- [3] Press key to continue (pid=19272)... [3] Gets a fd referring to the mountpoint without triggering the mount. While pid 19272 waits... # ls -l /proc/19272/fd/4 l--------- 1 root root 64 feb 13 12:34 /proc/19272/fd/4 -> /direct/data/d1 # ls -l /proc/19272/fd/4/ total 0 # ls -l /proc/19272/fd/5 lr-x------ 1 root root 64 feb 13 12:35 /proc/19272/fd/5 -> /direct/data/d1 # ls -l /proc/19272/fd/5/ total 0
Created attachment 18556 [details] Test program One possibility would switching from openat to openat2 and pass RESOLVE_NO_XDEV in the how structore. Then we will get EXDEV when crossing any mountpoint, then calling fstatfs() and fallback to name based for automounts or retying without RESOLVE_NO_XDEV for other types. # ./test2 /direct Target is /direct chddir(/direct) -> 0 openat(AT_FDCWD, data, O_RDONLY | O_NOFOLLOW | O_PATH) -> 3 openat(3, d1, O_RDONLY | O_NOFOLLOW | O_PATH) -> 4 openat2(AT_FDCWD, /proc/self/fd/4, ... how.resolve.RESOLVE_NO_XDEV) -> -1 Invalid cross-device link sbuf.f_type=0x187 It is autofs, fallback to name-based openat(3, d1, O_RDONLY | O_NOFOLLOW) -> 5 getdents(5) -> 1048576 . .. f1
Created attachment 18573 [details] Patch for master A possible fix. Pipeline: https://gitlab.com/samba-team/devel/samba/-/pipelines/1676040908