diff --git a/weed/mount/filehandle_map.go b/weed/mount/filehandle_map.go index 0fcf5196e5..bf0c71e919 100644 --- a/weed/mount/filehandle_map.go +++ b/weed/mount/filehandle_map.go @@ -57,7 +57,15 @@ func (i *FileHandleToInode) MarkInodeRenamed(inode uint64) { // Every open gets its own fh value over the shared FileHandle so that // RELEASE — which identifies nothing else about the dying description — can // scope per-open state (e.g. OFD lock owners) to the open that is closing. -func (i *FileHandleToInode) AcquireFileHandle(wfs *WFS, inode uint64, entry *filer_pb.Entry, versionTsNs int64, signature int32) (*FileHandle, FileHandleId, bool) { +// +// A handle whose counter already reached zero is draining its deferred flush: +// it stays in the map only so rename/unlink can still find it, and +// RemoveFileHandle will drop it (and every fh id minted for it) when the drain +// completes. Attaching here would hand the kernel an fh id that vanishes mid- +// open — reads on it return ENOENT, which the kernel reports to read() as EIO. +// Callers must treat a draining report as "wait for the pending flush, then +// retry the whole acquire", not as success. +func (i *FileHandleToInode) AcquireFileHandle(wfs *WFS, inode uint64, entry *filer_pb.Entry, versionTsNs int64, signature int32) (*FileHandle, FileHandleId, bool, bool) { i.Lock() defer i.Unlock() fh, found := i.inode2fh[inode] @@ -67,13 +75,16 @@ func (i *FileHandleToInode) AcquireFileHandle(wfs *WFS, inode uint64, entry *fil fh.entryVersionSignature.Store(signature) i.inode2fh[inode] = fh i.fh2inode[fh.fh] = inode - return fh, fh.fh, false + return fh, fh.fh, false, false + } + if fh.counter <= 0 { + return nil, 0, true, true } fh.counter++ openFh := FileHandleId(util.RandomUint64()) fh.fhs[openFh] = struct{}{} i.fh2inode[openFh] = inode - return fh, openFh, true + return fh, openFh, true, false } func (i *FileHandleToInode) ReleaseByHandle(fh FileHandleId) *FileHandle { diff --git a/weed/mount/filehandle_map_test.go b/weed/mount/filehandle_map_test.go new file mode 100644 index 0000000000..b5013df26d --- /dev/null +++ b/weed/mount/filehandle_map_test.go @@ -0,0 +1,43 @@ +package mount + +import ( + "testing" +) + +// A handle whose last open closed with a deferred flush stays in the map while +// the drain runs so rename/unlink can find it. A new open must NOT attach to it: +// the fh id it would mint is dropped by RemoveFileHandle, leaving kernel reads +// to fail with ENOENT — which the kernel reports to read() as EIO. +func TestAcquireFileHandleRefusesDrainingHandle(t *testing.T) { + wfs := &WFS{option: &Option{}} + fhMap := NewFileHandleToInode() + inode := uint64(12345) + + fh, _, existed, draining := fhMap.AcquireFileHandle(wfs, inode, nil, 0, 0) + if existed || draining || fh == nil { + t.Fatalf("first acquire: fh=%v existed=%v draining=%v", fh, existed, draining) + } + fh.asyncFlushPending = true + + // Last release with a deferred flush keeps the draining handle in the map. + released := fhMap.ReleaseByHandle(fh.fh) + if released != fh { + t.Fatalf("ReleaseByHandle returned %v, want the draining handle", released) + } + if _, found := fhMap.FindFileHandle(inode); !found { + t.Fatal("draining handle should stay in the map for rename/unlink") + } + + // A new open must not resurrect the draining handle. + fh2, openFh, existed, draining := fhMap.AcquireFileHandle(wfs, inode, nil, 0, 0) + if !draining || fh2 != nil { + t.Fatalf("acquire during drain: fh=%v openFh=%v existed=%v draining=%v, want draining", fh2, openFh, existed, draining) + } + + // After the drain removes the handle, the next acquire creates a fresh one. + fhMap.RemoveFileHandle(fh.fh, inode) + fh3, _, existed, draining := fhMap.AcquireFileHandle(wfs, inode, nil, 0, 0) + if draining || existed || fh3 == nil || fh3 == fh { + t.Fatalf("acquire after drain: fh=%v existed=%v draining=%v, want fresh handle", fh3, existed, draining) + } +} diff --git a/weed/mount/filehandle_read_remote_test.go b/weed/mount/filehandle_read_remote_test.go index 20fc5d06a8..f2d5aac868 100644 --- a/weed/mount/filehandle_read_remote_test.go +++ b/weed/mount/filehandle_read_remote_test.go @@ -118,7 +118,7 @@ func TestReadUncachedRemoteEntryDoesNotDeadlock(t *testing.T) { t.Cleanup(func() { wfs.metaCache.Shutdown() }) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: uint64(len(testServer.content))}, RemoteEntry: &filer_pb.RemoteEntry{RemoteSize: int64(len(testServer.content))}, diff --git a/weed/mount/weedfs_file_copy_range_test.go b/weed/mount/weedfs_file_copy_range_test.go index a91cfca78f..6224d91648 100644 --- a/weed/mount/weedfs_file_copy_range_test.go +++ b/weed/mount/weedfs_file_copy_range_test.go @@ -21,7 +21,7 @@ func TestWholeFileServerCopyCandidate(t *testing.T) { srcInode := wfs.inodeToPath.Lookup(srcPath, 1, false, false, 0, true) dstInode := wfs.inodeToPath.Lookup(dstPath, 1, false, false, 0, true) - srcHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ + srcHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ Name: "src.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, @@ -30,7 +30,7 @@ func TestWholeFileServerCopyCandidate(t *testing.T) { }, Content: []byte("hello"), }, 0, 0) - dstHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ + dstHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ Name: "dst.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, @@ -86,7 +86,7 @@ func TestCopyFileRangeUsesServerSideWholeFileCopy(t *testing.T) { srcInode := wfs.inodeToPath.Lookup(srcPath, 1, false, false, 0, true) dstInode := wfs.inodeToPath.Lookup(dstPath, 1, false, false, 0, true) - srcHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ + srcHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ Name: "src.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, @@ -95,7 +95,7 @@ func TestCopyFileRangeUsesServerSideWholeFileCopy(t *testing.T) { }, Content: []byte("hello"), }, 0, 0) - dstHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ + dstHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ Name: "dst.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, @@ -171,7 +171,7 @@ func TestCopyFileRangeDoesNotFallbackAfterCommittedServerCopyRefreshFailure(t *t srcInode := wfs.inodeToPath.Lookup(srcPath, 1, false, false, 0, true) dstInode := wfs.inodeToPath.Lookup(dstPath, 1, false, false, 0, true) - srcHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ + srcHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ Name: "src.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, @@ -182,7 +182,7 @@ func TestCopyFileRangeDoesNotFallbackAfterCommittedServerCopyRefreshFailure(t *t }, Content: []byte("hello"), }, 0, 0) - dstHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ + dstHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ Name: "dst.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100600, @@ -253,7 +253,7 @@ func TestCopyFileRangeReturnsEIOForAmbiguousServerSideCopy(t *testing.T) { srcInode := wfs.inodeToPath.Lookup(srcPath, 1, false, false, 0, true) dstInode := wfs.inodeToPath.Lookup(dstPath, 1, false, false, 0, true) - srcHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ + srcHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ Name: "src.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, @@ -262,7 +262,7 @@ func TestCopyFileRangeReturnsEIOForAmbiguousServerSideCopy(t *testing.T) { }, Content: []byte("hello"), }, 0, 0) - dstHandle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ + dstHandle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ Name: "dst.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100600, diff --git a/weed/mount/weedfs_file_fallocate_test.go b/weed/mount/weedfs_file_fallocate_test.go index d565e21bf6..c0ad15192b 100644 --- a/weed/mount/weedfs_file_fallocate_test.go +++ b/weed/mount/weedfs_file_fallocate_test.go @@ -22,7 +22,7 @@ func newOpenFileHandle(t *testing.T, fileSize uint64) (*WFS, *FileHandle) { wfs := newCopyRangeTestWFS() path := util.FullPath("/file.txt") inode := wfs.inodeToPath.Lookup(path, 1, false, false, 0, true) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644, diff --git a/weed/mount/weedfs_file_mkrm.go b/weed/mount/weedfs_file_mkrm.go index cd54eec281..213a97eea8 100644 --- a/weed/mount/weedfs_file_mkrm.go +++ b/weed/mount/weedfs_file_mkrm.go @@ -132,7 +132,20 @@ func (wfs *WFS) Create(cancel <-chan struct{}, in *fuse.CreateIn, name string, o // For deferred creates, bypass AcquireHandle (which calls maybeReadEntry // and would fail since the entry is not yet on the filer or in the meta cache). // We already have the entry from createRegularFile, so create the handle directly. - fileHandle, openFh, existed := wfs.fhMap.AcquireFileHandle(wfs, inode, newEntry, 0, 0) + var fileHandle *FileHandle + var openFh FileHandleId + var existed, draining bool + for { + fileHandle, openFh, existed, draining = wfs.fhMap.AcquireFileHandle(wfs, inode, newEntry, 0, 0) + if !draining { + break + } + // A prior incarnation's deferred flush is still draining on this + // inode; wait for it to release the handle before attaching ours. + if !wfs.waitForPendingAsyncFlush(ctx, inode) { + return fuse.EINTR + } + } if existed { // A create is authoritative for the entry it just made, so it takes // effect even on a handle that outlived a previous incarnation. diff --git a/weed/mount/weedfs_file_mkrm_test.go b/weed/mount/weedfs_file_mkrm_test.go index a8d8a2568e..b9c855b69e 100644 --- a/weed/mount/weedfs_file_mkrm_test.go +++ b/weed/mount/weedfs_file_mkrm_test.go @@ -267,7 +267,7 @@ func TestTruncateEntryClearsDirtyPagesForOpenHandle(t *testing.T) { }, } - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, entry, 0, 0) + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, entry, 0, 0) fh.RememberPath(fullPath) if err := fh.dirtyPages.AddPage(0, []byte("hello"), true, time.Now().UnixNano()); err != nil { @@ -315,7 +315,7 @@ func TestAccessChecksPermissions(t *testing.T) { fullPath := util.FullPath("/visible.txt") inode := wfs.inodeToPath.Lookup(fullPath, 1, false, false, 0, true) - handle, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + handle, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "visible.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0o640, diff --git a/weed/mount/weedfs_filehandle.go b/weed/mount/weedfs_filehandle.go index e71a5fd03c..e401d20756 100644 --- a/weed/mount/weedfs_filehandle.go +++ b/weed/mount/weedfs_filehandle.go @@ -9,69 +9,84 @@ import ( "github.com/seaweedfs/seaweedfs/weed/cluster/lock_manager" "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" + "github.com/seaweedfs/seaweedfs/weed/util" ) // AcquireHandle returns the shared handle for inode plus this open's own fh // value — the id handed to the kernel and seen again at RELEASE. func (wfs *WFS) AcquireHandle(ctx context.Context, inode uint64, flags, uid, gid uint32) (fileHandle *FileHandle, openFh FileHandleId, status fuse.Status) { - // If there is an in-flight async flush for this inode, wait for it to - // complete before reopening. Otherwise the new handle would be built - // from pre-close filer metadata and its next flush could overwrite the - // data that was just written asynchronously. - if !wfs.waitForPendingAsyncFlush(ctx, inode) { - return nil, 0, fuse.EINTR - } + var path util.FullPath + for { + // If there is an in-flight async flush for this inode, wait for it to + // complete before reopening. Otherwise the new handle would be built + // from pre-close filer metadata and its next flush could overwrite the + // data that was just written asynchronously. + if !wfs.waitForPendingAsyncFlush(ctx, inode) { + return nil, 0, fuse.EINTR + } - path, pathStatus := wfs.inodeToPath.GetPath(inode) - if pathStatus != fuse.OK { - return nil, 0, pathStatus - } + var pathStatus fuse.Status + path, pathStatus = wfs.inodeToPath.GetPath(inode) + if pathStatus != fuse.OK { + return nil, 0, pathStatus + } - // A fresh lookup returns the entry with the filer log position it - // reflects; the handle takes that entry and version as one decision in - // AcquireFileHandle, so a slower concurrent opener cannot - // overwrite a newer install. An existing handle keeps its own entry and - // version — they did not come from this lookup. - var entry *filer_pb.Entry - var entryVersionTsNs entryVersion - freshLookup := false - if existingFh, found := wfs.fhMap.FindFileHandle(inode); found { - entry = existingFh.UpdateEntry(func(entry *filer_pb.Entry) { - if entry != nil && existingFh.entry.Attributes == nil { - entry.Attributes = &filer_pb.FuseAttributes{} + // A fresh lookup returns the entry with the filer log position it + // reflects; the handle takes that entry and version as one decision in + // AcquireFileHandle, so a slower concurrent opener cannot + // overwrite a newer install. An existing handle keeps its own entry and + // version — they did not come from this lookup. + var entry *filer_pb.Entry + var entryVersionTsNs entryVersion + freshLookup := false + if existingFh, found := wfs.fhMap.FindFileHandle(inode); found { + entry = existingFh.UpdateEntry(func(entry *filer_pb.Entry) { + if entry != nil && existingFh.entry.Attributes == nil { + entry.Attributes = &filer_pb.FuseAttributes{} + } + }) + entryVersionTsNs = entryVersion{tsNs: existingFh.entryVersionTsNs.Load(), signature: existingFh.entryVersionSignature.Load()} + } else { + entry, entryVersionTsNs, status = wfs.maybeLoadEntry(ctx, path) + if status != fuse.OK { + return nil, 0, status } - }) - entryVersionTsNs = entryVersion{tsNs: existingFh.entryVersionTsNs.Load(), signature: existingFh.entryVersionSignature.Load()} - } else { - entry, entryVersionTsNs, status = wfs.maybeLoadEntry(ctx, path) - if status != fuse.OK { - return nil, 0, status + freshLookup = true } - freshLookup = true - } - if wormEnforced, _ := wfs.wormEnforcedForEntry(path, entry); wormEnforced && flags&fuse.O_ANYWRITE != 0 { - return nil, 0, fuse.EPERM - } - // Check unix permission bits for the requested access mode. With - // default_permissions the kernel already enforced them before this - // open, so the check (and its supplementary-group lookup) is redundant. - if !wfs.option.DefaultPermissions && entry != nil && entry.Attributes != nil { - fileUid, fileGid := entry.Attributes.Uid, entry.Attributes.Gid - if wfs.option.UidGidMapper != nil { - fileUid, fileGid = wfs.option.UidGidMapper.FilerToLocal(fileUid, fileGid) + if wormEnforced, _ := wfs.wormEnforcedForEntry(path, entry); wormEnforced && flags&fuse.O_ANYWRITE != 0 { + return nil, 0, fuse.EPERM } - if mask := openFlagsToAccessMask(flags); mask != 0 && !hasAccess(uid, gid, fileUid, fileGid, entry.Attributes.FileMode, mask) { - return nil, 0, fuse.EACCES + // Check unix permission bits for the requested access mode. With + // default_permissions the kernel already enforced them before this + // open, so the check (and its supplementary-group lookup) is redundant. + if !wfs.option.DefaultPermissions && entry != nil && entry.Attributes != nil { + fileUid, fileGid := entry.Attributes.Uid, entry.Attributes.Gid + if wfs.option.UidGidMapper != nil { + fileUid, fileGid = wfs.option.UidGidMapper.FilerToLocal(fileUid, fileGid) + } + if mask := openFlagsToAccessMask(flags); mask != 0 && !hasAccess(uid, gid, fileUid, fileGid, entry.Attributes.FileMode, mask) { + return nil, 0, fuse.EACCES + } } - } - // need to AcquireFileHandle again to ensure correct handle counter - var existed bool - fileHandle, openFh, existed = wfs.fhMap.AcquireFileHandle(wfs, inode, entry, entryVersionTsNs.tsNs, entryVersionTsNs.signature) - fileHandle.RememberPath(path) - if existed && freshLookup { - // Another opener created the handle while our lookup was in flight; - // install only state that provably improves on what it holds. - fileHandle.installAckedEntry(entry, entryVersionTsNs.tsNs, entryVersionTsNs.signature) + // need to AcquireFileHandle again to ensure correct handle counter + var existed, draining bool + fileHandle, openFh, existed, draining = wfs.fhMap.AcquireFileHandle(wfs, inode, entry, entryVersionTsNs.tsNs, entryVersionTsNs.signature) + if draining { + // A RELEASE slipped between waitForPendingAsyncFlush and this + // attach: the handle's last open closed and its deferred flush + // is draining. The pending-flush flag is registered under the + // same mutex that dropped the counter, so the next iteration + // blocks on the drain (or finds the handle already removed) + // and rebuilds state from post-flush metadata. + continue + } + fileHandle.RememberPath(path) + if existed && freshLookup { + // Another opener created the handle while our lookup was in flight; + // install only state that provably improves on what it holds. + fileHandle.installAckedEntry(entry, entryVersionTsNs.tsNs, entryVersionTsNs.signature) + } + break } // Acquire distributed lock for write opens. The lock is held with @@ -86,7 +101,7 @@ func (wfs *WFS) AcquireHandle(ctx context.Context, inode uint64, flags, uid, gid if fileHandle.dlmLock == nil { // No lock server is reachable: proceeding would silently drop // cross-mount write serialization, so fail the open instead. - wfs.fhMap.ReleaseByHandle(openFh) + wfs.ReleaseHandle(openFh) return nil, 0, fuse.Status(syscall.EAGAIN) } glog.V(1).Infof("DLM lock acquired for %s", path) diff --git a/weed/mount/weedfs_invalidate_open_handle_test.go b/weed/mount/weedfs_invalidate_open_handle_test.go index 752891249f..7cddb221de 100644 --- a/weed/mount/weedfs_invalidate_open_handle_test.go +++ b/weed/mount/weedfs_invalidate_open_handle_test.go @@ -195,7 +195,7 @@ func TestUpdateEventRefreshesOpenFileHandle(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -260,7 +260,7 @@ func TestQueuedEventDoesNotRollBackNewerLocalState(t *testing.T) { wfs.inodeToPath.MarkChildrenCached(util.FullPath("/dir")) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -302,7 +302,7 @@ func TestBufferedBuildEventReinvalidatesOnCompletion(t *testing.T) { wfs.inodeToPath.Lookup(util.FullPath("/dir"), time.Now().Unix(), true, false, 0, false) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -352,7 +352,7 @@ func TestUncachedDirStaleStoreEntryDoesNotMaskEvent(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -388,7 +388,7 @@ func TestQueuedEventOlderThanFlushedStateIsIgnored(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -424,7 +424,7 @@ func TestSaveEntryKeepsOpenHandleAheadOfOlderEvents(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -462,7 +462,7 @@ func TestQueuedEventDoesNotRollBackHandleOpenedAfterEnqueue(t *testing.T) { // Stall the single invalidation worker on an unrelated handle's lock so // queued events outlive the open below. blockerInode := wfs.inodeToPath.Lookup(util.FullPath("/other/blocker"), time.Now().Unix(), false, false, 0, false) - blockerFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, blockerInode, &filer_pb.Entry{ + blockerFh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, blockerInode, &filer_pb.Entry{ Name: "blocker", Attributes: &filer_pb.FuseAttributes{FileSize: 1}, }, 0, 0) @@ -523,7 +523,7 @@ func TestAbortedBuildEventDoesNotRollBackLaterOpen(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{lookupSize: 200, lookupLogTsNs: 2000}) blockerInode := wfs.inodeToPath.Lookup(util.FullPath("/other/blocker"), time.Now().Unix(), false, false, 0, false) - blockerFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, blockerInode, &filer_pb.Entry{ + blockerFh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, blockerInode, &filer_pb.Entry{ Name: "blocker", Attributes: &filer_pb.FuseAttributes{FileSize: 1}, }, 0, 0) @@ -590,7 +590,7 @@ func TestEventDuringOpenLookupIsFenced(t *testing.T) { startFakeFiler(t, wfs, fake) blockerInode := wfs.inodeToPath.Lookup(util.FullPath("/other/blocker"), time.Now().Unix(), false, false, 0, false) - blockerFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, blockerInode, &filer_pb.Entry{ + blockerFh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, blockerInode, &filer_pb.Entry{ Name: "blocker", Attributes: &filer_pb.FuseAttributes{FileSize: 1}, }, 0, 0) @@ -667,7 +667,7 @@ func TestRemoteCacheResponseVersionFencesUndeliveredEvents(t *testing.T) { } inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -699,7 +699,7 @@ func TestEventlessSaveAckStillFencesOlderEvents(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{updateEventless: true, updateLogTsNs: 2000}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, }, 0, 0) @@ -884,7 +884,7 @@ func TestAlreadyReflectedEventDoesNotDestroyDirtyPages(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, }, 0, 0) @@ -998,7 +998,7 @@ func TestAlreadyReflectedEventPreservesDirtyWrites(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, }, 0, 0) @@ -1077,7 +1077,7 @@ func TestServerSideCopyInstallEnrollsInBase(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 100}, }, 0, 0) @@ -1198,7 +1198,7 @@ func TestCommittedCopyWithFailedReadbackAdoptsItsEvent(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 100}, }, 0, 0) @@ -1311,7 +1311,7 @@ func TestFlushAckCancelsPendingCopyEventAdoption(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 100}, }, 0, 0) @@ -1356,7 +1356,7 @@ func TestAckedSaveInstallsIntoRacingOpenHandle(t *testing.T) { // The handle opened after the setattr path found none, before the ack. inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -1378,7 +1378,7 @@ func TestAckedSaveInstallsIntoRacingOpenHandle(t *testing.T) { // A dirty handle is left alone entirely: neither entry nor version. dirtyInode := wfs.inodeToPath.Lookup(util.FullPath("/dir/dirty"), time.Now().Unix(), false, false, 0, false) - dirtyFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dirtyInode, &filer_pb.Entry{ + dirtyFh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dirtyInode, &filer_pb.Entry{ Name: "dirty", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -1434,7 +1434,7 @@ func TestVacateEventPreservesDirtyPages(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, }, 0, 0) @@ -1469,7 +1469,7 @@ func TestCopyAdoptRejectsForeignEvent(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 100}, }, 0, 0) @@ -1500,7 +1500,7 @@ func TestRemoteDownloadBaseMappedToLocal(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{cacheSize: 200, cacheUid: 2000, cacheLogTsNs: 1000}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, RemoteEntry: &filer_pb.RemoteEntry{RemoteSize: 200}, @@ -1545,7 +1545,7 @@ func TestForeignDeleteMarksHandleDeleted(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, }, 0, 0) @@ -1603,7 +1603,7 @@ func TestStaleRemoteDownloadDoesNotRollBack(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{cacheSize: 100, cacheLogTsNs: 1000}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, RemoteEntry: &filer_pb.RemoteEntry{RemoteSize: 200}, @@ -1637,7 +1637,7 @@ func TestRemoteOnlyHandleTakesUnversionedDownload(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{cacheSize: 100}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 100}, RemoteEntry: &filer_pb.RemoteEntry{RemoteSize: 100}, @@ -1662,7 +1662,7 @@ func TestCopyAdoptRejectsForeignMetadataChange(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200, FileMode: 0100644}, }, 0, 0) @@ -1697,7 +1697,7 @@ func TestForeignRenameDoesNotMarkHandleDeleted(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, }, 0, 0) @@ -1752,7 +1752,7 @@ func TestCopyAdoptAppliesForeignTouchToCleanHandle(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200, Mtime: 100}, }, 0, 0) @@ -1788,7 +1788,7 @@ func TestUnversionedRemoteDownloadDoesNotOverwriteVersioned(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{cacheSize: 100}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, RemoteEntry: &filer_pb.RemoteEntry{RemoteSize: 200}, @@ -1860,7 +1860,7 @@ func TestTouchBeforeCopyEventKeepsPostCopyWrites(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 100, Mtime: 100}, }, 0, 0) @@ -1924,7 +1924,7 @@ func TestRejectedDownloadDoesNotRollBackCache(t *testing.T) { wfs.metaCache.WaitForEntryInvalidations() inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, Chunks: []*filer_pb.FileChunk{{FileId: "1,ab1", Size: 200}}, @@ -1959,7 +1959,7 @@ func TestRemoteOnlyHandleRefusesKnownOlderDownload(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{cacheSize: 100, cacheLogTsNs: 1000}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200}, RemoteEntry: &filer_pb.RemoteEntry{RemoteSize: 200}, @@ -1981,7 +1981,7 @@ func TestForeignChmodPreservesDirtyPages(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 200, FileMode: 0100644}, }, 0, 0) @@ -2013,12 +2013,12 @@ func TestRenameOverExistingMarksReplacedHandleDeleted(t *testing.T) { wfs := newInvalidateTestWFS(t) srcInode := wfs.inodeToPath.Lookup(util.FullPath("/dir/src"), time.Now().Unix(), false, false, 0, false) - srcFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ + srcFh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, srcInode, &filer_pb.Entry{ Name: "src", Attributes: &filer_pb.FuseAttributes{FileSize: 100}, }, 0, 0) dstInode := wfs.inodeToPath.Lookup(util.FullPath("/dir/dst"), time.Now().Unix(), false, false, 0, false) - dstFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ + dstFh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, dstInode, &filer_pb.Entry{ Name: "dst", Attributes: &filer_pb.FuseAttributes{FileSize: 900}, }, 0, 0) @@ -2053,7 +2053,7 @@ func TestAckFromAnotherFilerIsNotDroppedBehindForeignFence(t *testing.T) { wfs := newInvalidateTestWFS(t) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) diff --git a/weed/mount/weedfs_release_flock_test.go b/weed/mount/weedfs_release_flock_test.go index 676f787988..09bc7e6913 100644 --- a/weed/mount/weedfs_release_flock_test.go +++ b/weed/mount/weedfs_release_flock_test.go @@ -20,7 +20,7 @@ func TestReleaseDropsFlockWhileFlushBlocked(t *testing.T) { startFakeFiler(t, wfs, &fakeFilerServer{}) inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/f"), time.Now().Unix(), false, false, 0, false) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "f", Attributes: &filer_pb.FuseAttributes{}, }, 0, 0) @@ -91,8 +91,8 @@ func TestReleaseDropsOfdLocks(t *testing.T) { Name: "f", Attributes: &filer_pb.FuseAttributes{}, } - _, openFh, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, entry, 0, 0) - _, siblingFh, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, entry, 0, 0) + _, openFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, entry, 0, 0) + _, siblingFh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, entry, 0, 0) if siblingFh == openFh { t.Fatal("sibling open must get its own fh value") } diff --git a/weed/mount/weedfs_remote_rename_test.go b/weed/mount/weedfs_remote_rename_test.go index 08a586cb6a..8f8c78d078 100644 --- a/weed/mount/weedfs_remote_rename_test.go +++ b/weed/mount/weedfs_remote_rename_test.go @@ -71,7 +71,7 @@ func TestRemoteRenameReplayLeavesTheTargetAlone(t *testing.T) { oldPath, newPath := util.FullPath("/dir/file"), util.FullPath("/dir/renamed") inode := wfs.inodeToPath.Lookup(oldPath, time.Now().Unix(), false, false, 0, true) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) @@ -100,7 +100,7 @@ func TestRenameBelowTheVersionFenceStillMoves(t *testing.T) { oldPath, newPath := util.FullPath("/dir/file"), util.FullPath("/dir/renamed") inode := wfs.inodeToPath.Lookup(oldPath, time.Now().Unix(), false, false, 0, true) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "file", Attributes: &filer_pb.FuseAttributes{FileSize: 88}, }, 0, 0) diff --git a/weed/mount/weedfs_xattr_test.go b/weed/mount/weedfs_xattr_test.go index 51ffb1cd8e..035553c277 100644 --- a/weed/mount/weedfs_xattr_test.go +++ b/weed/mount/weedfs_xattr_test.go @@ -26,7 +26,7 @@ func TestSetXAttrCopiesValueBuffer(t *testing.T) { path := util.FullPath("/aaa.txt") inode := wfs.inodeToPath.Lookup(path, 1, false, false, 0, true) - fh, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ + fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, &filer_pb.Entry{ Name: "aaa.txt", Attributes: &filer_pb.FuseAttributes{ FileMode: 0100644,