vfs: Fix TestWriteFileDoubleClose with --vfs-cache-mode >= writes

This was causing the file to be closed on Flush() instead of Release()
when the file was opened with O_TRUNC.
This commit is contained in:
Nick Craig-Wood 2018-02-26 21:26:32 +00:00
parent c3d0f68923
commit b91bd32489
2 changed files with 20 additions and 22 deletions

View File

@ -31,6 +31,7 @@ type RWFileHandle struct {
flags int // open flags flags int // open flags
osPath string // path to the file in the cache osPath string // path to the file in the cache
writeCalled bool // if any Write() methods have been called writeCalled bool // if any Write() methods have been called
changed bool // file contents was changed in any other way
} }
// Check interfaces // Check interfaces
@ -146,7 +147,7 @@ func (fh *RWFileHandle) openPending(truncate bool) (err error) {
// if the object wasn't found AND O_CREATE is set then // if the object wasn't found AND O_CREATE is set then
// ignore error as we are about to create the file // ignore error as we are about to create the file
fh.file.setSize(0) fh.file.setSize(0)
fh.writeCalled = true fh.changed = true
} else { } else {
return errors.Wrap(err, "open RW handle failed to cache file") return errors.Wrap(err, "open RW handle failed to cache file")
} }
@ -159,7 +160,7 @@ func (fh *RWFileHandle) openPending(truncate bool) (err error) {
} else { } else {
// Set the size to 0 since we are truncating and flag we need to write it back // Set the size to 0 since we are truncating and flag we need to write it back
fh.file.setSize(0) fh.file.setSize(0)
fh.writeCalled = true fh.changed = true
if fh.flags&os.O_CREATE == 0 && fh.file.exists() { if fh.flags&os.O_CREATE == 0 && fh.file.exists() {
// create an empty file if it exists on the source // create an empty file if it exists on the source
err = ioutil.WriteFile(fh.osPath, []byte{}, 0600) err = ioutil.WriteFile(fh.osPath, []byte{}, 0600)
@ -215,6 +216,20 @@ func (fh *RWFileHandle) Node() Node {
return fh.file return fh.file
} }
// Returns whether the file needs to be written back.
//
// If write hasn't been called and the file hasn't been changed in any other
// way we haven't modified it so we don't need to transfer it
//
// Must be called with fh.mu held
func (fh *RWFileHandle) modified() bool {
if !fh.writeCalled && !fh.changed {
fs.Debugf(fh.logPrefix(), "not modified so not transferring")
return false
}
return true
}
// close the file handle returning EBADF if it has been // close the file handle returning EBADF if it has been
// closed already. // closed already.
// //
@ -301,24 +316,6 @@ func (fh *RWFileHandle) Close() error {
return fh.close() return fh.close()
} }
func (fh *RWFileHandle) modified() bool {
rdwrMode := fh.flags & accessModeMask
// no writes means no transfer?
if rdwrMode == os.O_RDONLY && fh.flags&os.O_TRUNC == 0 {
fs.Debugf(fh.logPrefix(), "read only and not truncating so not transferring")
return false
}
// If write hasn't been called and we aren't creating or
// truncating the file then we haven't modified it so don't
// need to transfer it
if !fh.writeCalled && fh.flags&(os.O_CREATE|os.O_TRUNC) == 0 {
fs.Debugf(fh.logPrefix(), "not modified so not transferring")
return false
}
return true
}
// Flush is called each time the file or directory is closed. // Flush is called each time the file or directory is closed.
// Because there can be multiple file descriptors referring to a // Because there can be multiple file descriptors referring to a
// single opened file, Flush can be called multiple times. // single opened file, Flush can be called multiple times.
@ -507,7 +504,7 @@ func (fh *RWFileHandle) Truncate(size int64) (err error) {
if err = fh.openPending(size == 0); err != nil { if err = fh.openPending(size == 0); err != nil {
return err return err
} }
fh.writeCalled = true fh.changed = true
fh.file.setSize(size) fh.file.setSize(size)
return fh.File.Truncate(size) return fh.File.Truncate(size)
} }

View File

@ -350,7 +350,8 @@ func TestRWFileHandleWriteAt(t *testing.T) {
// Preconditions // Preconditions
assert.Equal(t, int64(0), offset()) assert.Equal(t, int64(0), offset())
assert.True(t, fh.opened) assert.True(t, fh.opened)
assert.True(t, fh.writeCalled) assert.False(t, fh.writeCalled)
assert.True(t, fh.changed)
// Write the data // Write the data
n, err := fh.WriteAt([]byte("hello**"), 0) n, err := fh.WriteAt([]byte("hello**"), 0)