From 93157e09b8b6ee5884ed2b3dc1ef09f731fb5e52 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 13 Nov 2026 03:15:50 -0800 Subject: [PATCH] mount: check the flush target after every lock acquisition A flush whose name kept changing published to the name chosen before its last lock wait. Check after each acquisition and return a retryable error once the attempts run out. Co-Authored-By: Claude Opus 5.5 --- weed/mount/weedfs_file_sync.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/weed/mount/weedfs_file_sync.go b/weed/mount/weedfs_file_sync.go index e333229110..ae3a1b2af2 100644 --- a/weed/mount/weedfs_file_sync.go +++ b/weed/mount/weedfs_file_sync.go @@ -206,21 +206,24 @@ func (wfs *WFS) doFlush(ctx context.Context, fh *FileHandle, uid, gid uint32, al // needed here. The local fhLockTable lock below serializes within this mount. func (wfs *WFS) flushMetadataToFiler(ctx context.Context, fh *FileHandle, dir, name string, uid, gid uint32) error { fileFullPath, dir, name := wfs.flushTarget(fh, dir, name) - // Attribute acknowledgement and local retention must complete before a - // whole-entry flush can publish. Take this before the handle's active lock. - unlock := wfs.lockMetadataPublication(fileFullPath) - fhActiveLock := fh.wfs.fhLockTable.AcquireLock("doFlush", fh.fh, util.ExclusiveLock) - // An unlink or rename can land before the locks are held. - for attempt := 0; attempt < 3; attempt++ { + var unlock func() + var fhActiveLock *util.ActiveLock + // An unlink or rename can land while the flush waits for its locks. + for attempt := 0; ; attempt++ { + // Attribute acknowledgement and local retention must complete before a + // whole-entry flush can publish. Take this before the handle's active lock. + unlock = wfs.lockMetadataPublication(fileFullPath) + fhActiveLock = fh.wfs.fhLockTable.AcquireLock("doFlush", fh.fh, util.ExclusiveLock) nowPath, nowDir, nowName := wfs.flushTarget(fh, dir, name) if nowPath == fileFullPath && nowDir == dir && nowName == name { break } fh.wfs.fhLockTable.ReleaseLock(fh.fh, fhActiveLock) unlock() + if attempt == 3 { + return fmt.Errorf("flush %s: name changed while waiting for its locks, now %s", fileFullPath, nowPath) + } fileFullPath, dir, name = nowPath, nowDir, nowName - unlock = wfs.lockMetadataPublication(fileFullPath) - fhActiveLock = fh.wfs.fhLockTable.AcquireLock("doFlush", fh.fh, util.ExclusiveLock) } defer func() { fh.wfs.fhLockTable.ReleaseLock(fh.fh, fhActiveLock)