From 5b1eed35eea57655b36be163f0aeadb55d89cf40 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Wed, 8 Jun 2016 22:39:35 +0200 Subject: [PATCH] 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. --- internal/fusefrontend/file.go | 15 +++++++++++++-- internal/fusefrontend/fs_dir.go | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index 3fa5a48..62303df 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -286,7 +286,9 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) { f.fdLock.RLock() defer f.fdLock.RUnlock() 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()) 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()) - 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) } diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index 5fea438..e946087 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -190,7 +190,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) { } return fuse.ToStatus(err) } - // Delete "gocryptfs.diriv.rmdir.INODENUMBER" + // Delete "gocryptfs.diriv.rmdir.XYZ" err = syscall.Unlinkat(int(parentDirFd.Fd()), tmpName) if err != nil { toggledlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err)