fusefrontend: Utimens: convert ENOENT to EBADF

If /proc/self/fd/X did not exist, the actual error is that the file
descriptor was invalid.

go-fuse's pathfs prefers using an open fd even for path-based operations
but does not take any locks to prevent the fd from being closed.
Instead, it retries the operation by path if it get EBADF. So this
change allows the retry logic to work correctly.

This fixes the error

    rsync: failed to set times on "/tmp/ping.Kgw.mnt/linux-3.0/[...]/.dvb_demux.c.N7YlEM":
    No such file or directory (2)

that was triggered by pingpong-rsync.bash.
This commit is contained in:
Jakob Unterwurzacher 2016-06-08 22:39:35 +02:00
parent 37d824c9a8
commit 5b1eed35ee
2 changed files with 14 additions and 3 deletions

View File

@ -286,7 +286,9 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
f.fdLock.RLock() f.fdLock.RLock()
defer f.fdLock.RUnlock() defer f.fdLock.RUnlock()
if f.released { if f.released {
// The file descriptor has been closed concurrently. // The file descriptor has been closed concurrently, which also means
// the wlock has been freed. Exit here so we don't crash trying to access
// it.
toggledlog.Warn.Printf("ino%d fh%d: Write on released file", f.ino, f.intFd()) toggledlog.Warn.Printf("ino%d fh%d: Write on released file", f.ino, f.intFd())
return 0, fuse.EBADF return 0, fuse.EBADF
} }
@ -514,5 +516,14 @@ func (f *file) Utimens(a *time.Time, m *time.Time) fuse.Status {
} }
fn := fmt.Sprintf("/proc/self/fd/%d", f.fd.Fd()) fn := fmt.Sprintf("/proc/self/fd/%d", f.fd.Fd())
return fuse.ToStatus(syscall.UtimesNano(fn, ts)) err := syscall.UtimesNano(fn, ts)
if err != nil {
toggledlog.Debug.Printf("UtimesNano on %q failed: %v", fn, err)
}
if err == syscall.ENOENT {
// If /proc/self/fd/X did not exist, the actual error is that the file
// descriptor was invalid.
return fuse.EBADF
}
return fuse.ToStatus(err)
} }

View File

@ -190,7 +190,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
} }
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Delete "gocryptfs.diriv.rmdir.INODENUMBER" // Delete "gocryptfs.diriv.rmdir.XYZ"
err = syscall.Unlinkat(int(parentDirFd.Fd()), tmpName) err = syscall.Unlinkat(int(parentDirFd.Fd()), tmpName)
if err != nil { if err != nil {
toggledlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err) toggledlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err)