From 4d04609bb8417e1bc00a8987d1407e2a6c9d452b Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 18 May 2026 01:02:58 -0700 Subject: [PATCH] fix(mount): don't release file handles from FUSE Forget (#9529) fix(mount): don't release file handles from Forget Forget(nodeid, nlookup) only decrements the kernel inode lookup count. File handle lifecycle belongs to FUSE Open/Release. Driving the FH refcount from Forget coupled two unrelated counters and could tear down a still-live handle if Forget ever raced ahead of Release. Drop the ReleaseByInode call (and the now-unused method). --- weed/mount/filehandle_map.go | 25 ------------------------- weed/mount/weedfs_forget.go | 10 ++++------ 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/weed/mount/filehandle_map.go b/weed/mount/filehandle_map.go index f8463f1bb..8a81eb1fa 100644 --- a/weed/mount/filehandle_map.go +++ b/weed/mount/filehandle_map.go @@ -66,31 +66,6 @@ func (i *FileHandleToInode) AcquireFileHandle(wfs *WFS, inode uint64, entry *fil return fh } -func (i *FileHandleToInode) ReleaseByInode(inode uint64) *FileHandle { - i.Lock() - defer i.Unlock() - fh, found := i.inode2fh[inode] - if !found { - return nil - } - // If the counter is already <= 0, a prior Release already started the - // drain. Return nil to prevent double-processing (e.g. Forget after Release). - if fh.counter <= 0 { - return nil - } - fh.counter-- - if fh.counter <= 0 { - if fh.asyncFlushPending { - // Handle stays in fhMap so rename/unlink can find it during drain. - return fh - } - delete(i.inode2fh, inode) - delete(i.fh2inode, fh.fh) - return fh - } - return nil -} - func (i *FileHandleToInode) ReleaseByHandle(fh FileHandleId) *FileHandle { i.Lock() defer i.Unlock() diff --git a/weed/mount/weedfs_forget.go b/weed/mount/weedfs_forget.go index 2502c3929..29fc84251 100644 --- a/weed/mount/weedfs_forget.go +++ b/weed/mount/weedfs_forget.go @@ -63,13 +63,11 @@ Side effects: increments the lookup count on success */ func (wfs *WFS) Forget(nodeid, nlookup uint64) { + // Forget only decrements the kernel's inode lookup count. File handle + // lifecycle is driven independently by FUSE Open/Release — touching the + // fhMap here would couple two unrelated refcounts and could tear down a + // still-live handle if Forget ever raced ahead of Release. wfs.inodeToPath.Forget(nodeid, nlookup, func(dir util.FullPath) { wfs.metaCache.DeleteFolderChildren(context.Background(), dir) }) - // ReleaseByInode returns nil if the handle is already draining (counter - // was already <= 0 from a prior Release). Only non-async handles that - // reach counter 0 here need cleanup. - if fhToRelease := wfs.fhMap.ReleaseByInode(nodeid); fhToRelease != nil { - fhToRelease.ReleaseHandle() - } }