Seems like the kernel doesn't follow the fdescfs symlink when checking if the target points to a directory for openat (and open) with the O_DIRECTORY flag. Unless you've primed it with an "ls -l" in the directory (or something similar that does a stat() call). Then it starts to work. To "reset" - unmount and remount the fdescfs filesystem again (Thought I was going insane when debugging a problem with Samba 4.18 and Samba failed but my test program worked. Turned out my test program was doing a stat() call before attempting this which primed the cache...) root@runur00:~ # egrep compat /etc/fstab none /compat/linux/dev/fd fdescfs rw,linrdlnk 0 root@runur00:~ # ./t ./t: openat(AT_FDCWD, "/compat/linux/dev/fd/3", O_DIRECTORY, 0): Not a directory root@runur00:~ # ls /compat/linux/dev/fd/ 0 1 2 3 4 root@runur00:~ # ./t ./t: openat(AT_FDCWD, "/compat/linux/dev/fd/3", O_DIRECTORY, 0): Not a directory root@runur00:~ # ls -l /compat/linux/dev/fd/ total 0 lr-xr-xr-x 1 root wheel 0 Jun 20 15:57 0 -> /dev/pts/0 lr-xr-xr-x 1 root wheel 0 Jun 20 15:57 1 -> /dev/pts/0 lr-xr-xr-x 1 root wheel 0 Jun 20 15:57 2 -> /dev/pts/0 lr-xr-xr-x 1 root wheel 0 Jun 20 15:57 3 -> /root lr-xr-xr-x 1 root wheel 0 Jun 20 15:57 4 -> /etc/spwd.db root@runur00:~ # ./t /compat/linux/dev/fd/3: OK root@runur00:~ # umount /compat/linux/dev/fd root@runur00:~ # mount /compat/linux/dev/fd root@runur00:~ # ./t ./t: openat(AT_FDCWD, "/compat/linux/dev/fd/3", O_DIRECTORY, 0): Not a directory Test program: #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> int main(int argc, char *argv[]) { int dfd, tfd; char buf[2048]; dfd = open(".", O_PATH); sprintf(buf, "/compat/linux/dev/fd/%d", dfd); tfd = openat(AT_FDCWD, buf, O_DIRECTORY, 0); if (tfd < 0) { fprintf(stderr, "%s: openat(AT_FDCWD, \"%s\", O_DIRECTORY, 0): %s\n", argv[0], buf, strerror(errno)); exit(1); } printf("%s: OK\n", buf); exit(0); }
PR 255625 / D30131 fixes that. I believe it was not committed waiting on your feedback. But even with D30131 applied, the result of your test program is EACCES, because you opened fd 3 with O_PATH. You need nodup option for that to work, but it is kind of incompatible with linrdlnk for obvious reasons.
It's not just related to O_DIRECTORY but a more general problem with fdescfs... root@runur00:/export/build/samba # umount /compat/linux/dev/fd root@runur00:/export/build/samba # mount /compat/linux/dev/fd root@runur00:/export/build/samba # ./t -d /home/peter86 RUNUR00 open("/home/peter86", O_PATH) -> 3 facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] openat(3, "RUNUR00", O_RDONLY) -> 4 facl(4, ACE_GETACLCNT) -> 3 acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> -1 [errno=78 (Function not implemented)] openat(3, "RUNUR00", O_PATH) -> 4 facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> -1 [errno=78 (Function not implemented)] openat(4, "", O_EMPTY_PATH) -> 5 facl(5, ACE_GETACLCNT) -> 3 open("/compat/linux/dev/fd/4", O_RDONLY) -> -1 [errno=20 (Not a directory)] root@runur00:/export/build/samba # ls -ld /home/peter86/RUNUR00 drwx------+ 2 peter86 employee-liu.se 2 Jun 20 10:52 /home/peter86/RUNUR00 root@runur00:/export/build/samba # ./t -ssd /home/peter86 RUNUR00 open("/home/peter86", O_PATH) -> 3 facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] openat(3, "RUNUR00", O_RDONLY) -> 4 facl(4, ACE_GETACLCNT) -> 3 stat("/compat/linux/dev/fd/4") -> 0 [type=symlink, size=0, uid=0, gid=0] readlink("/compat/linux/dev/fd/4") -> 28 [path=/export/home/peter86/RUNUR00] stat("/compat/linux/dev/fd/4") -> 0 [type=dir, size=2, uid=1003258, gid=100001000] acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3 openat(3, "RUNUR00", O_PATH) -> 4 facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] stat("/compat/linux/dev/fd/4") -> 0 [type=dir, size=2, uid=1003258, gid=100001000] stat("/compat/linux/dev/fd/4") -> 0 [type=dir, size=2, uid=1003258, gid=100001000] acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3 openat(4, "", O_EMPTY_PATH) -> 5 facl(5, ACE_GETACLCNT) -> 3 open("/compat/linux/dev/fd/4", O_RDONLY) -> 5 facl(5, ACE_GETACLCNT) -> 3 root@runur00:/export/build/samba # ./t -d /home/peter86 RUNUR00 open("/home/peter86", O_PATH) -> 3 facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] openat(3, "RUNUR00", O_RDONLY) -> 4 facl(4, ACE_GETACLCNT) -> 3 acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3 openat(3, "RUNUR00", O_PATH) -> 4 facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3 openat(4, "", O_EMPTY_PATH) -> 5 facl(5, ACE_GETACLCNT) -> 3 open("/compat/linux/dev/fd/4", O_RDONLY) -> 5 facl(5, ACE_GETACLCNT) -> 3 See how the first stat() call to a fd in the fdescfs also gives invalid size, uid & gid data but as soon as that stat call has pulled in the information about the target things work fine.
Created attachment 242920 [details] Test program
Try https://reviews.freebsd.org/D40700
(In reply to Konstantin Belousov from comment #4) A custom kernel with that fix seems to solve the problem! # umount /compat/linux/dev/fd # mount /compat/linux/dev/fd # ./tst -axrd /home/peter86 RUNUR00 open("/home/peter86", O_PATH) -> 3 facl(3, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] extattr_list_fd(3, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 extattr_list_fd(3, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_fd(3, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0 openat(3, "RUNUR00", O_RDONLY) -> 4 facl(4, ACE_GETACLCNT) -> 3 facl(4, ACE_GETACL) -> 3 extattr_list_fd(4, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 extattr_list_fd(4, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_fd(4, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0 acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3 acl("/compat/linux/dev/fd/4", ACE_GETACL) -> 3 extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 openat(3, "RUNUR00", O_PATH) -> 4 facl(4, ACE_GETACLCNT) -> -1 [errno=9 (Bad file descriptor)] extattr_list_fd(4, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 extattr_list_fd(4, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_fd(4, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0 acl("/compat/linux/dev/fd/4", ACE_GETACLCNT) -> 3 acl("/compat/linux/dev/fd/4", ACE_GETACL) -> 3 extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_file("/compat/linux/dev/fd/4", EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 openat(4, "", O_EMPTY_PATH) -> 5 facl(5, ACE_GETACLCNT) -> 3 facl(5, ACE_GETACL) -> 3 extattr_list_fd(5, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 extattr_list_fd(5, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_fd(5, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0 open("/compat/linux/dev/fd/4", O_RDONLY|O_DIRECTORY) -> 5 facl(5, ACE_GETACLCNT) -> 3 facl(5, ACE_GETACL) -> 3 extattr_list_fd(5, EXTATTR_NAMESPACE_SYSTEM, NULL, 0) -> 0 extattr_list_fd(5, EXTATTR_NAMESPACE_USER, NULL, 0) -> 0 extattr_list_fd(5, EXTATTR_NAMESPACE_USER, 0x824992018, 0) -> 0
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=3bffa2262328e4ff1737516f176107f607e7bc76 commit 3bffa2262328e4ff1737516f176107f607e7bc76 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2023-06-22 13:30:59 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2023-06-27 10:43:17 +0000 fdescfs: improve linrdlnk mount option Instead of using VV_READLINK vnode flag and checking it in one place, just assign VLNK type to the Fdesc vnodes for linrdlnk mounts. Then all places where symlinks needs to be followed, e.g. lookup(), are handled. PR: 272127 Reported by: Peter Eriksson <pen@lysator.liu.se> Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D40700 sys/fs/fdescfs/fdesc_vnops.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=109230f383ac5a60a7bd4e40bbde361c28c430cf commit 109230f383ac5a60a7bd4e40bbde361c28c430cf Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2023-06-22 13:30:59 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2023-07-04 03:06:46 +0000 fdescfs: improve linrdlnk mount option PR: 272127 (cherry picked from commit 3bffa2262328e4ff1737516f176107f607e7bc76) sys/fs/fdescfs/fdesc_vnops.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
I suspect you are trying to use a linux specific fdescfs linrdlnk mount for a native application?
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=3905309dfeeb89f03b09c347f7ac0a863faa3975 commit 3905309dfeeb89f03b09c347f7ac0a863faa3975 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2023-07-11 05:03:49 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2023-07-13 01:14:20 +0000 fdescfs: add a mount option rdlnk which changes /dev/fd/N files types to symbolic link with the behavior of symbolic links. PR: 272127 Reported by: Peter Eriksson <pen@lysator.liu.se> Reviewed by: dchagin Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D40969 sys/fs/fdescfs/fdesc.h | 1 + sys/fs/fdescfs/fdesc_vfsops.c | 2 ++ sys/fs/fdescfs/fdesc_vnops.c | 15 ++++++++++----- 3 files changed, 13 insertions(+), 5 deletions(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=da56eae4404d4d273cc4a8b7d8f05547bb188599 commit da56eae4404d4d273cc4a8b7d8f05547bb188599 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2023-07-11 05:03:49 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2023-07-20 12:20:09 +0000 fdescfs: add a mount option rdlnk PR: 272127 (cherry picked from commit 3905309dfeeb89f03b09c347f7ac0a863faa3975) sys/fs/fdescfs/fdesc.h | 1 + sys/fs/fdescfs/fdesc_vfsops.c | 2 ++ sys/fs/fdescfs/fdesc_vnops.c | 16 ++++++++++------ 3 files changed, 13 insertions(+), 6 deletions(-)