diff --git a/vfs/file.go b/vfs/file.go index a85aaea00..63513d44d 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -21,6 +21,7 @@ type File struct { mu sync.Mutex // protects the following o fs.Object // NB o may be nil if file is being written leaf string // leaf name of the object + rwOpenCount int // number of open files on this handle writers []Handle // writers for this file readWriters int // how many RWFileHandle are open for writing readWriterClosing bool // is a RWFileHandle currently cosing? @@ -138,6 +139,31 @@ func (f *File) delWriter(h Handle, modifiedCacheFile bool) (lastWriterAndModifie return } +// addRWOpen should be called by ReadWriteHandle when they have +// actually opened the file for read or write. +func (f *File) addRWOpen() { + f.mu.Lock() + f.rwOpenCount++ + f.mu.Unlock() +} + +// delRWOpen should be called by ReadWriteHandle when they have closed +// an actually opene file for read or write. +func (f *File) delRWOpen() { + f.mu.Lock() + f.rwOpenCount-- + f.mu.Unlock() +} + +// rwOpens returns how many active open ReadWriteHandles there are. +// Note that file handles which are in pending open state aren't +// counted. +func (f *File) rwOpens() int { + f.mu.Lock() + defer f.mu.Unlock() + return f.rwOpenCount +} + // finishWriterClose resets the readWriterClosing flag func (f *File) finishWriterClose() { f.mu.Lock() diff --git a/vfs/read_write.go b/vfs/read_write.go index 5243220fc..2b8e9525b 100644 --- a/vfs/read_write.go +++ b/vfs/read_write.go @@ -192,6 +192,7 @@ func (fh *RWFileHandle) openPending(truncate bool) (err error) { } fh.File = fd fh.opened = true + fh.file.addRWOpen() fh.d.addObject(fh.file) // make sure the directory has this object in it now return nil } @@ -246,7 +247,12 @@ func (fh *RWFileHandle) close() (err error) { return ECLOSED } fh.closed = true - defer fh.d.vfs.cache.close(fh.remote) + defer func() { + if fh.opened { + fh.file.delRWOpen() + } + fh.d.vfs.cache.close(fh.remote) + }() rdwrMode := fh.flags & accessModeMask writer := rdwrMode != os.O_RDONLY diff --git a/vfs/read_write_test.go b/vfs/read_write_test.go index 52e7066c8..075a24cb3 100644 --- a/vfs/read_write_test.go +++ b/vfs/read_write_test.go @@ -74,9 +74,15 @@ func TestRWFileHandleMethodsRead(t *testing.T) { // Size assert.Equal(t, int64(16), fh.Size()) + // No opens yet + assert.Equal(t, 0, fh.file.rwOpens()) + // Read 1 assert.Equal(t, "0", rwReadString(t, fh, 1)) + // Open after the read + assert.Equal(t, 1, fh.file.rwOpens()) + // Read remainder assert.Equal(t, "123456789abcdef", rwReadString(t, fh, 256)) @@ -101,6 +107,9 @@ func TestRWFileHandleMethodsRead(t *testing.T) { assert.Equal(t, nil, fh.Close()) assert.True(t, fh.closed) + // No opens again + assert.Equal(t, 0, fh.file.rwOpens()) + // Close again assert.Equal(t, ECLOSED, fh.Close()) } @@ -266,6 +275,10 @@ func TestRWFileHandleMethodsWrite(t *testing.T) { vfs, fh := rwHandleCreateWriteOnly(t, r) defer cleanup(t, r, vfs) + // 1 opens since we opened with O_CREATE and the file didn't + // exist in the cache + assert.Equal(t, 1, fh.file.rwOpens()) + // String assert.Equal(t, "file1 (rw)", fh.String()) assert.Equal(t, "", (*RWFileHandle)(nil).String()) @@ -293,6 +306,9 @@ func TestRWFileHandleMethodsWrite(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 5, n) + // Open after the write + assert.Equal(t, 1, fh.file.rwOpens()) + // Offset #2 assert.Equal(t, int64(5), offset()) assert.Equal(t, int64(5), node.Size()) @@ -323,6 +339,9 @@ func TestRWFileHandleMethodsWrite(t *testing.T) { // Close assert.NoError(t, fh.Close()) + // No opens again + assert.Equal(t, 0, fh.file.rwOpens()) + // Check double close err = fh.Close() assert.Equal(t, ECLOSED, err)