From 922117e22708e1fca4d808a7ace86b50ab690ff3 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 13 Nov 2026 01:09:31 -0800 Subject: [PATCH] mount: carry an alias unlink's stored entry into the open handle Removing one of several hard links lowers the stored link count and stamps a new ctime, and the handle may still hold the removed name. Look up the entry at the name the handle flushes through and adopt it, so the next content flush matches the stored entry, writes the right count, and attribute saves address the surviving name. Co-Authored-By: Claude Opus 5.5 --- weed/mount/weedfs_file_mkrm.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/weed/mount/weedfs_file_mkrm.go b/weed/mount/weedfs_file_mkrm.go index 06ec73d1ef..f191d1ddc8 100644 --- a/weed/mount/weedfs_file_mkrm.go +++ b/weed/mount/weedfs_file_mkrm.go @@ -1,6 +1,7 @@ package mount import ( + "bytes" "context" "fmt" "syscall" @@ -358,9 +359,14 @@ func (wfs *WFS) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name strin } // Another link still names the inode, so its open handle keeps flushing - // through that name. + // through that name, over the count and ctime the filer stored there. if isHardLink && markedInode != 0 { - if _, status := wfs.inodeToPath.GetPath(markedInode); status == fuse.OK { + if survivor, status := wfs.inodeToPath.GetPath(markedInode); status == fuse.OK { + if fh, found := wfs.fhMap.FindFileHandle(markedInode); found { + if stored, tsNs, signature, err := filer_pb.GetEntry(ctx, wfs, survivor); err == nil && bytes.Equal(stored.GetHardLinkId(), entry.HardLinkId) { + fh.adoptLinkChange(stored, tsNs, signature) + } + } wfs.clearHandleDeleted(markedInode, deleteEpoch) } }