mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 23:14:21 +00:00
fix(mount): avoid self-notify deadlock in Link and CopyFileRange handlers (#9110)
The Link and CopyFileRange FUSE request handlers were calling fuseServer.InodeNotify (and EntryNotify for copy) synchronously while the kernel was still waiting for the request's reply on the same /dev/fuse fd. Notifications share that fd, so the syscall.Write can block indefinitely when the kernel hasn't drained its queue yet, hanging the entire mount. A goroutine dump from a stuck mount showed the Link handler blocked in syscall.Write inside InodeNotify while the server's read loop kept waiting for new requests. Drop the synchronous notifies. The local meta cache is still updated inline, so subsequent filesystem ops see the fresh state; the kernel's attr/dentry caches re-fetch once their TTL expires.
This commit is contained in:
@@ -251,7 +251,11 @@ func (wfs *WFS) applyServerSideWholeFileCopyResult(fhIn, fhOut *FileHandle, dstP
|
||||
}
|
||||
fhOut.dirtyMetadata = false
|
||||
wfs.updateServerSideWholeFileCopyMetaCache(dstPath, entry)
|
||||
wfs.invalidateCopyDestinationCache(fhOut.inode, dstPath)
|
||||
// Note: we intentionally skip fuseServer.InodeNotify/EntryNotify here.
|
||||
// This runs inside the CopyFileRange request handler; those notifies
|
||||
// would write onto the same /dev/fuse fd the kernel is still waiting
|
||||
// on for this request's reply, deadlocking the mount. The kernel will
|
||||
// re-read attrs once its attr-cache TTL expires.
|
||||
}
|
||||
|
||||
func (wfs *WFS) updateServerSideWholeFileCopyMetaCache(dstPath util.FullPath, entry *filer_pb.Entry) {
|
||||
@@ -501,16 +505,3 @@ func (wfs *WFS) filerCopyJWT() security.EncodedJwt {
|
||||
return security.GenJwtForFilerServer(wfs.option.FilerSigningKey, wfs.option.FilerSigningExpiresAfterSec)
|
||||
}
|
||||
|
||||
func (wfs *WFS) invalidateCopyDestinationCache(inode uint64, fullPath util.FullPath) {
|
||||
if wfs.fuseServer != nil {
|
||||
if status := wfs.fuseServer.InodeNotify(inode, 0, -1); status != fuse.OK {
|
||||
glog.V(4).Infof("CopyFileRange invalidate inode %d: %v", inode, status)
|
||||
}
|
||||
dir, name := fullPath.DirAndName()
|
||||
if parentInode, found := wfs.inodeToPath.GetInode(util.FullPath(dir)); found {
|
||||
if status := wfs.fuseServer.EntryNotify(parentInode, name); status != fuse.OK {
|
||||
glog.V(4).Infof("CopyFileRange invalidate entry %s: %v", fullPath, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,9 +231,9 @@ func (wfs *WFS) syncHardLinkSiblings(inode uint64, authoritativeEntry *filer_pb.
|
||||
glog.V(4).Infof("syncHardLinkSiblings update %s: %v", p, err)
|
||||
}
|
||||
}
|
||||
if wfs.fuseServer != nil {
|
||||
if status := wfs.fuseServer.InodeNotify(inode, 0, -1); status != fuse.OK {
|
||||
glog.V(4).Infof("syncHardLinkSiblings invalidate inode %d: %v", inode, status)
|
||||
}
|
||||
}
|
||||
// Note: we deliberately do NOT call fuseServer.InodeNotify here. That
|
||||
// call would be made from the FUSE Link request handler goroutine, and
|
||||
// writes onto the same /dev/fuse fd that the kernel is still waiting to
|
||||
// read the Link reply from — causing a self-notify deadlock. The kernel
|
||||
// will re-stat siblings once its attr-cache TTL expires.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user