diff --git a/weed/mount/weedfs_metadata_flush.go b/weed/mount/weedfs_metadata_flush.go index fdcafa0ef5..1edee9d6ee 100644 --- a/weed/mount/weedfs_metadata_flush.go +++ b/weed/mount/weedfs_metadata_flush.go @@ -99,6 +99,10 @@ func (wfs *WFS) flushFileMetadata(fh *FileHandle) error { if !fh.dirtyMetadata { return nil } + // Unlink marks under this lock; publishing would recreate the name. + if fh.isDeleted { + return nil + } fileFullPath := fh.FullPath() dir, name := fileFullPath.DirAndName() diff --git a/weed/mount/weedfs_metadata_flush_unlinked_test.go b/weed/mount/weedfs_metadata_flush_unlinked_test.go new file mode 100644 index 0000000000..8033646739 --- /dev/null +++ b/weed/mount/weedfs_metadata_flush_unlinked_test.go @@ -0,0 +1,31 @@ +//go:build !freebsd + +package mount + +import ( + "testing" + + "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" +) + +// A file unlinked while open, before its deferred create reached the filer, +// must not be created by the periodic metadata flush. +func TestPeriodicFlushSkipsUnlinkedHandle(t *testing.T) { + wfs, fake, fh, inode := openLinkTestFile(t) + fake.mu.Lock() + delete(fake.records, "tmp") + fake.mu.Unlock() + fh.baseEntry.Store(nil) + wfs.markHandleDeleted(inode) + fh.UpdateEntry(func(e *filer_pb.Entry) { + e.Chunks = append(e.Chunks, linkHandleChunk(2, 100)) + e.Attributes.FileSize = 200 + }) + fh.dirtyMetadata = true + if err := wfs.flushFileMetadata(fh); err != nil { + t.Fatalf("periodic flush: %v", err) + } + if fake.stored("tmp") != nil { + t.Fatal("the periodic flush recreated the unlinked name") + } +}