diff --git a/vfs/vfs.go b/vfs/vfs.go index 31116c822..1d6ac1631 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -234,9 +234,10 @@ func New(ctx context.Context, f fs.Fs, opt *vfscommon.Options) *VFS { defer activeMu.Unlock() configName := fs.ConfigString(f) for _, activeVFS := range active[configName] { - if vfs.Opt == activeVFS.Opt { + // A VFS whose last reference has gone is being shut down + // but may not have removed itself from the cache yet. + if vfs.Opt == activeVFS.Opt && activeVFS.Hold() { fs.Debugf(f, "Reusing VFS from active cache") - activeVFS.inUse.Add(1) cancel() return activeVFS } diff --git a/vfs/vfs_test.go b/vfs/vfs_test.go index c9f9f95cf..710674a80 100644 --- a/vfs/vfs_test.go +++ b/vfs/vfs_test.go @@ -174,6 +174,22 @@ func TestVFSHold(t *testing.T) { assert.False(t, vfs.Hold(), "VFS held after being shut down") } +// TestVFSNewShuttingDown checks New doesn't reuse a VFS which is being +// shut down but hasn't yet removed itself from the active cache. +func TestVFSNewShuttingDown(t *testing.T) { + r := fstest.NewRun(t) + vfs := New(context.Background(), r.Fremote, nil) + + // The state Shutdown leaves the VFS in while it waits for activeMu + vfs.inUse.Store(0) + vfs2 := New(context.Background(), r.Fremote, nil) + assert.NotSame(t, vfs, vfs2, "reused a VFS being shut down") + assert.Equal(t, int32(0), vfs.inUse.Load()) + + vfs.Shutdown() + vfs2.Shutdown() +} + // TestVFSNewWithOpts sees if the New command works properly func TestVFSNewWithOpts(t *testing.T) { var opt = vfscommon.Opt