Closed KongzhangHao closed 1 year ago
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:349
2023-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:349
2023-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:349
2023-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:349
2023-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 archprctl(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 https://github.com/Sherlock-Holo/fuse3/pull/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!
I found that when running
ln target_file link_file
in a mounted directory wheretarget_file
exists andlink_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 thatlookup(target_file)
andlookup(link_file)
are called, whilelookup(target_file)
finds the inode andlookup(link_file)
doesn't find anything, which is expected. But then it says becauselink_file
doesn't exist, there is an ENOENT error, which is very weird. If I create a file calledlink_file
, it shows the error:ln: failed to create hard link 'link_file': file exists
. Also,link()
in thefilesystem
trait is never called and the opcode for it is never received.