diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/file.go | 20 | 
1 files changed, 15 insertions, 5 deletions
| diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index e374956..3fa5a48 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -6,6 +6,7 @@ import (  	"bytes"  	"fmt"  	"io" +	"log"  	"os"  	"sync"  	"syscall" @@ -21,11 +22,15 @@ import (  // File - based on loopbackFile in go-fuse/fuse/nodefs/files.go  type file struct {  	fd *os.File - +	// Has Release() already been called on this file? This also means that the +	// wlock entry has been freed, so let's not crash trying to access it. +	// Due to concurrency, Release can overtake other operations. These will +	// return EBADF in that case. +	released bool  	// fdLock prevents the fd to be closed while we are in the middle of  	// an operation.  	// Every FUSE entrypoint should RLock(). The only user of Lock() is -	// Release(), which closes the fd, hence has to acquire an exclusive lock. +	// Release(), which closes the fd and sets "released" to true.  	fdLock sync.RWMutex  	// Was the file opened O_WRONLY? @@ -280,8 +285,9 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {  func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {  	f.fdLock.RLock()  	defer f.fdLock.RUnlock() -	if f.fd.Fd() < 0 { +	if f.released {  		// The file descriptor has been closed concurrently. +		toggledlog.Warn.Printf("ino%d fh%d: Write on released file", f.ino, f.intFd())  		return 0, fuse.EBADF  	}  	wlock.lock(f.ino) @@ -308,7 +314,11 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {  // Release - FUSE call, close file  func (f *file) Release() {  	f.fdLock.Lock() +	if f.released { +		log.Panicf("ino%d fh%d: double release", f.ino, f.intFd()) +	}  	f.fd.Close() +	f.released = true  	f.fdLock.Unlock()  	wlock.unregister(f.ino) @@ -342,9 +352,9 @@ func (f *file) Fsync(flags int) (code fuse.Status) {  func (f *file) Truncate(newSize uint64) fuse.Status {  	f.fdLock.RLock()  	defer f.fdLock.RUnlock() -	if f.fd.Fd() < 0 { +	if f.released {  		// The file descriptor has been closed concurrently. -		toggledlog.Warn.Printf("ino%d fh%d: Truncate on forgotten file", f.ino, f.intFd()) +		toggledlog.Warn.Printf("ino%d fh%d: Truncate on released file", f.ino, f.intFd())  		return fuse.EBADF  	}  	wlock.lock(f.ino) | 
