aboutsummaryrefslogtreecommitdiff
path: root/internal/syscallcompat/eintr.go
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-10-14 13:40:12 +0200
committerJakob Unterwurzacher2020-10-14 13:40:12 +0200
commitec3eaf0b8776500a9762555eac754b6c893420fd (patch)
treea230d3aff6bf0c97d8bde0d9715edce5fb39ec6a /internal/syscallcompat/eintr.go
parentaf4c1fb7a3f428ff704af22294ad955d05ed41dd (diff)
syscallcompat: don't retry Close()
After Close() returns, the fd is dead, even if we received EINTR. Don't retry, we could shoot down an unrelated fd that received the same fd number.
Diffstat (limited to 'internal/syscallcompat/eintr.go')
-rw-r--r--internal/syscallcompat/eintr.go27
1 files changed, 23 insertions, 4 deletions
diff --git a/internal/syscallcompat/eintr.go b/internal/syscallcompat/eintr.go
index 122af9b..f0a82f5 100644
--- a/internal/syscallcompat/eintr.go
+++ b/internal/syscallcompat/eintr.go
@@ -11,6 +11,9 @@ import (
//
// This is needed because CIFS throws lots of EINTR errors:
// https://github.com/rfjakob/gocryptfs/issues/483
+//
+// Don't use retryEINTR() with syscall.Close()!
+// See https://code.google.com/p/chromium/issues/detail?id=269623 .
func retryEINTR(op func() error) error {
for {
err := op()
@@ -40,9 +43,25 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
return fd, err
}
-// Close wraps syscall.Close.
+// Flush is a helper for the FUSE command FLUSH.
// Retries on EINTR.
-func Close(fd int) (err error) {
- err = retryEINTR(func() error { return syscall.Close(fd) })
- return err
+func Flush(fd int) error {
+ for {
+ // Flushing is achieved by closing a dup'd fd.
+ newFd, err := syscall.Dup(fd)
+ if err == syscall.EINTR {
+ continue
+ }
+ if err != nil {
+ return err
+ }
+ err = syscall.Close(newFd)
+ // Even if we get EINTR here, newFd is dead - see
+ // https://code.google.com/p/chromium/issues/detail?id=269623 .
+ // We have to make a new one with Dup(), so continue at the top.
+ if err == syscall.EINTR {
+ continue
+ }
+ return err
+ }
}