Problem with hard link support
KongzhangHao opened this issue · comments
I found that when running ln target_file link_file
in a mounted directory where target_file
exists and link_file
does not exist, it shows an error: ln: failed to create hard link 'link_file' => 'target_file': No such file or directory
. When checking the log, it shows that lookup(target_file)
and lookup(link_file)
are called, while lookup(target_file)
finds the inode and lookup(link_file)
doesn't find anything, which is expected. But then it says because link_file
doesn't exist, there is an ENOENT error, which is very weird. If I create a file called link_file
, it shows the error: ln: failed to create hard link 'link_file': file exists
. Also, link()
in the filesystem
trait is never called and the opcode for it is never received.
I update the memfs example, implement the link
method, and check the hard link
the log reports
2023-01-15T04:43:21.974053Z DEBUG fuse3::raw::session: receive opcode FUSE_GETATTR
at src/raw/session.rs:3492023-01-15T04:43:21.974151Z DEBUG fuse3::raw::session: getattr unique 222 inode 3
at src/raw/session.rs:959
in fuse3::raw::session::fuse_getattr
in fuse3::raw::session::handle_getattr with request: Request { unique: 222, uid: 1000, gid: 1000, pid: 39849 }, in_header: fuse_in_header { len: 56, opcode: 3, unique: 222, nodeid: 3, uid: 1000, gid: 1000, pid: 39849, padding: 0 }2023-01-15T04:43:21.977295Z DEBUG fuse3::raw::session: receive opcode FUSE_LOOKUP
at src/raw/session.rs:3492023-01-15T04:43:21.977348Z DEBUG fuse3::raw::session: lookup unique 224 name "a" in parent 1
at src/raw/session.rs:850
in fuse3::raw::session::fuse_lookup
in fuse3::raw::session::handle_lookup with request: Request { unique: 224, uid: 1000, gid: 1000, pid: 39853 }, in_header: fuse_in_header { len: 42, opcode: 1, unique: 224, nodeid: 1, uid: 1000, gid: 1000, pid: 39853, padding: 0 }2023-01-15T04:43:21.977373Z DEBUG fuse3::raw::session: lookup response fuse_entry_out { nodeid: 2, generation: 0, entry_valid: 1, attr_valid: 1, entry_valid_nsec: 0, attr_valid_nsec: 0, attr: fuse_attr { ino: 2, size: 0, blocks: 0, atime: 0, mtime: 0, ctime: 0, atimensec: 0, mtimensec: 0, ctimensec: 0, mode: 16877, nlink: 0, uid: 0, gid: 0, rdev: 0, blksize: 0, padding: 0 } }
at src/raw/session.rs:871
in fuse3::raw::session::fuse_lookup
in fuse3::raw::session::handle_lookup with request: Request { unique: 224, uid: 1000, gid: 1000, pid: 39853 }, in_header: fuse_in_header { len: 42, opcode: 1, unique: 224, nodeid: 1, uid: 1000, gid: 1000, pid: 39853, padding: 0 }2023-01-15T04:43:21.977433Z DEBUG fuse3::raw::session: receive opcode FUSE_LOOKUP
at src/raw/session.rs:3492023-01-15T04:43:21.977475Z DEBUG fuse3::raw::session: lookup unique 226 name "123.txt" in parent 2
at src/raw/session.rs:850
in fuse3::raw::session::fuse_lookup
in fuse3::raw::session::handle_lookup with request: Request { unique: 226, uid: 1000, gid: 1000, pid: 39853 }, in_header: fuse_in_header { len: 48, opcode: 1, unique: 226, nodeid: 2, uid: 1000, gid: 1000, pid: 39853, padding: 0 }2023-01-15T04:43:21.977498Z DEBUG fuse3::raw::session: lookup response fuse_entry_out { nodeid: 4, generation: 0, entry_valid: 1, attr_valid: 1, entry_valid_nsec: 0, attr_valid_nsec: 0, attr: fuse_attr { ino: 4, size: 4, blocks: 0, atime: 0, mtime: 0, ctime: 0, atimensec: 0, mtimensec: 0, ctimensec: 0, mode: 33188, nlink: 0, uid: 0, gid: 0, rdev: 0, blksize: 0, padding: 0 } }
at src/raw/session.rs:871
in fuse3::raw::session::fuse_lookup
in fuse3::raw::session::handle_lookup with request: Request { unique: 226, uid: 1000, gid: 1000, pid: 39853 }, in_header: fuse_in_header { len: 48, opcode: 1, unique: 226, nodeid: 2, uid: 1000, gid: 1000, pid: 39853, padding: 0 }2023-01-15T04:43:21.977559Z DEBUG fuse3::raw::session: receive opcode FUSE_LOOKUP
at src/raw/session.rs:3492023-01-15T04:43:21.977601Z DEBUG fuse3::raw::session: lookup unique 228 name "bbb.txt" in parent 3
at src/raw/session.rs:850
in fuse3::raw::session::fuse_lookup
in fuse3::raw::session::handle_lookup with request: Request { unique: 228, uid: 1000, gid: 1000, pid: 39853 }, in_header: fuse_in_header { len: 48, opcode: 1, unique: 228, nodeid: 3, uid: 1000, gid: 1000, pid: 39853, padding: 0 }
that's so strange, when running ln a b
, kernel expect b should be exists
the ln
strace is
execve("/usr/bin/ln", ["ln", "../a/123.txt", "bbb.txt"], 0x7ffd405da150 /* 64 vars /) = 0
brk(NULL) = 0x55d99438c000
arch_prctl(0x3001 / ARCH_??? /, 0x7ffed768dba0) = -1 EINVAL (无效的参数)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=194271, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 194271, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa79dd50000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P4\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1953472, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa79dd4e000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 1994384, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa79db67000
mmap(0x7fa79db89000, 1421312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7fa79db89000
mmap(0x7fa79dce4000, 356352, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17d000) = 0x7fa79dce4000
mmap(0x7fa79dd3b000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d4000) = 0x7fa79dd3b000
mmap(0x7fa79dd41000, 52880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa79dd41000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa79db64000
arch_prctl(ARCH_SET_FS, 0x7fa79db64740) = 0
set_tid_address(0x7fa79db64a10) = 39853
set_robust_list(0x7fa79db64a20, 24) = 0
rseq(0x7fa79db65060, 0x20, 0, 0x53053053) = 0
mprotect(0x7fa79dd3b000, 16384, PROT_READ) = 0
mprotect(0x55d992972000, 4096, PROT_READ) = 0
mprotect(0x7fa79ddb1000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=81921024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7fa79dd50000, 194271) = 0
getrandom("\x39\x83\x0f\xc3\x56\x4d\xa4\x6e", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0x55d99438c000
brk(0x55d9943ad000) = 0x55d9943ad000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=6213312, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 6213312, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa79d400000
close(3) = 0
linkat(AT_FDCWD, "../a/123.txt", AT_FDCWD, "bbb.txt", 0) = -1 ENOENT (没有那个文件或目录)
newfstatat(AT_FDCWD, "../a/123.txt", {st_mode=S_IFREG|0644, st_size=4, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2998, ...}, AT_EMPTY_PATH) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
read(3, "", 4096) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/share/locale/zh_CN.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh_CN.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh_CN/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=359611, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 359611, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa79db0c000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=3916, ...}, AT_EMPTY_PATH) = 0
read(3, "# GNU libc iconv configuration.\n"..., 4096) = 3916
read(3, "", 4096) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
newfstatat(3, "", {st_mode=S_IFDIR|0755, st_size=48, ...}, AT_EMPTY_PATH) = 0
getdents64(3, 0x55d994394500 /* 3 entries /, 32768) = 96
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.d/gconv-modules-extra.conf", O_RDONLY|O_CLOEXEC) = 4
newfstatat(4, "", {st_mode=S_IFREG|0644, st_size=53974, ...}, AT_EMPTY_PATH) = 0
read(4, "# GNU libc iconv configuration.\n"..., 4096) = 4096
read(4, "B1002//\tJUS_I.B1.002//\nmodule\tJU"..., 4096) = 4096
read(4, "59-5//\nalias\tISO_8859-5//\t\tISO-8"..., 4096) = 4096
read(4, "59-16//\t\tINTERNAL\t\tISO8859-16\t1\n"..., 4096) = 4096
read(4, "-SE-A\t1\nmodule\tINTERNAL\t\tEBCDIC-"..., 4096) = 4096
read(4, "97\t\t1\n\n#\tfrom\t\t\tto\t\t\tmodule\t\tcos"..., 4096) = 4096
read(4, "1\n\n#\tfrom\t\t\tto\t\t\tmodule\t\tcost\nal"..., 4096) = 4096
brk(0x55d9943ce000) = 0x55d9943ce000
read(4, "6//\t\tIBM1046//\nalias\tCP1046//\t\tI"..., 4096) = 4096
read(4, "\tto\t\t\tmodule\t\tcost\nalias\tRUSCII/"..., 4096) = 4096
read(4, "03//\nmodule\tCSN_369103//\t\tINTERN"..., 4096) = 4096
read(4, "\tmodule\t\tcost\nalias\tISO-IR-8-1//"..., 4096) = 4096
read(4, "IBM1156\t\t1\n\n#\tfrom\t\t\tto\t\t\tmodule"..., 4096) = 4096
read(4, "\t\tIBM1166//\nalias\tCP1166//\t\tIBM1"..., 4096) = 4096
read(4, "alias\tROMAN9//\t\tHP-ROMAN9//\nalia"..., 4096) = 726
read(4, "", 4096) = 0
close(4) = 0
getdents64(3, 0x55d994394500 / 0 entries */, 32768) = 0
close(3) = 0
futex(0x7fa79dd4098c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(2, "ln: ", 4ln: ) = 4
write(2, "\346\227\240\346\263\225\345\210\233\345\273\272\347\241\254\351\223\276\346\216\245 'bbb.txt' "..., 49无法创建硬链接 'bbb.txt' => '../a/123.txt') = 49
openat(AT_FDCWD, "/usr/share/locale/zh_CN.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh_CN.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录)
openat(AT_FDCWD, "/usr/share/locale/zh_CN/LC_MESSAGES/libc.mo", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=129064, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 129064, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa79dd60000
close(3) = 0
write(2, ": \346\262\241\346\234\211\351\202\243\344\270\252\346\226\207\344\273\266\346\210\226\347\233\256\345\275\225", 29: 没有那个文件或目录) = 29
write(2, "\n", 1
) = 1
lseek(0, 0, SEEK_CUR) = -1 ESPIPE (非法 seek 操作)
close(0) = 0
close(1) = 0
close(2) = 0
exit_group(1) = ?
+++ exited with 1 +++
I did some investigation and the problem seems to be with linkat()
called by the kernel (i.e., linkat(AT_FDCWD, "../a/123.txt", AT_FDCWD, "bbb.txt", 0) = -1 ENOENT (没有那个文件或目录)
in the above strace log). In the linux implementation of linkat
(https://elixir.bootlin.com/linux/v6.2-rc3/source/fs/namei.c#L4553), it calls filename_lookup
on target file and filename_create
on the link file. Both filename_lookup
and filename_create
call lookup
, but they are with different flags (filename_create
has an additional flag LOOKUP_CREATE
). Is it possible that they are calling lookup with different flags but fuse3 cannot receive that?
FWIW link works for me.
FWIW link works for me.
I think the problem should occur in the Filesystem
implement, as @KongzhangHao says maybe the lookup
implement should check the flags to distinguish the normal lookup and the link lookup?
EDIT:
https://pkg.go.dev/bazil.org/fuse#LookupRequest i read other fuse library, their lookup only have the name argument, no flags argument
It seems that the lookup
function in the FileSystem
trait doesn't have flag in its interface. Is it because the fuse3 binary doesn't support flags in its lookup
interface? If so then it might be a problem with fuse3 binary?
What binary? This crate does not involve any such thing. There isn't any flags
field because the FUSE protocol does not include any such field in the FUSE_LOOKUP operation. The only thing that the fuse server gets during a lookup is the parent's node id and the file name.
Yeah that's fair enough. I was thinking of the fusermount binary in Linux.
in the example memfs, the reason for the hard link error is the nlink
filed is incorrect which return by lookup
implement,
I modify the memfs example #61 and test success on my computer
@KongzhangHao could you check your Filesystem
, is the nlink correct?
I fixed the nlink and it is working perfectly. Thanks for your help!