The fuse_internal_cache_attrs() call modifies the vattr of the vnode along
with its cached metadata. These fields are supposed to be protected by the
vnode lock, but calling the function from fuse_internal_do_getattr() is
done only with shared locking, not exlcusive. Upgrade the vnode lock to
exclusive before updating its metadata.
Details
- Reviewers
asomers
Diff Detail
- Repository
- rG FreeBSD src repository
- Lint
Lint Passed - Unit
No Test Coverage - Build Status
Buildable 70333 Build 67216: arc lint + arc unit
Event Timeline
Thanks for working on this! I was actually working on the exact same problem myself last week. And I came up with a very similar solution. But then I realized that it wouldn't work :( . The cached attrs also need to be modified in paths where the vnode lock cannot be upgraded. So my plan is to add a mutex just to protect them. I started work on it last week. But now I'm on vacation, so I can't resume work for a few more days. But thanks for your interest in fuse.
Makes sense! In case it helps, I found another place in FUSE with a similar problem - a normally read-only operation VFS operation requiring a lock upgrade to manage cached state - another one is when trying to execute a binary when the server sets the direct IO flag:
VNASSERT failed: locked not true at
/root/freebsd-src/sys/kern/vfs_subr.c:5816 (assert_vop_elocked)
0xfffffe02b7e70dc0: type VREG state VSTATE_CONSTRUCTED op
0xffffffff85464720
usecount 1, writecount -1, refcount 1 seqc users 0
hold count flags ()
flags ()
v_object 0xfffffe02b48b81e0 ref 0 pages 0 cleanbuf 0 dirtybuf 0
lock type fuse: SHARED (count 1)
nodeid: 4121, parent nodeid: 0, nlookup: 2, flag: 0x200
panic: fuse_filehandle_init: vnode is not exclusive locked but should be
cpuid = 2
time = 1769988829
KDB: stack backtrace:
db_trace_self_wrapper() at 0xffffffff805b4145 =
db_trace_self_wrapper+0xa5/frame 0xfffffe02ace54af0
kdb_backtrace() at 0xffffffff812f2746 = kdb_backtrace+0xc6/frame
0xfffffe02ace54c50
vpanic() at 0xffffffff81242f64 = vpanic+0x214/frame 0xfffffe02ace54df0
panic() at 0xffffffff81242d45 = panic+0xb5/frame 0xfffffe02ace54eb0
assert_vop_elocked() at 0xffffffff8142d56c =
assert_vop_elocked+0x14c/frame 0xfffffe02ace54f60
fuse_filehandle_init() at 0xffffffff8543f7ce =
fuse_filehandle_init+0x22e/frame 0xfffffe02ace54fd0
fuse_filehandle_open() at 0xffffffff8543f480 =
fuse_filehandle_open+0x2c0/frame 0xfffffe02ace550f0
VOP_OPEN_APV() at 0xffffffff81d66c35 = VOP_OPEN_APV+0xf5/frame
0xfffffe02ace55150
exec_check_permissions() at 0xffffffff811acc9d =
exec_check_permissions+0x4ed/frame 0xfffffe02ace55310
kern_execve() at 0xffffffff811a854b = kern_execve+0xe8b/frame
0xfffffe02ace55bd0
sys_execve() at 0xffffffff811a6ffa = sys_execve+0x12a/frame
0xfffffe02ace55d10
amd64_syscall() at 0xffffffff81bf0611 = amd64_syscall+0x481/frame
0xfffffe02ace55f30
fast_syscall_common() at 0xffffffff81ba7bdb =
fast_syscall_common+0xf8/frame 0xfffffe02ace55f30
--- syscall (59, FreeBSD ELF64, execve), rip = 0x20b9f6e6cd6a, rsp =
0x20b9f3d1f298, rbp = 0x20b9f3d1f3e0 ---
KDB: enter: panicFWIW a dedicated mutex for the cached attrs sounds great. I will abandon this diff since you are looking into this :)