From ec3eaf0b8776500a9762555eac754b6c893420fd Mon Sep 17 00:00:00 2001
From: Jakob Unterwurzacher
Date: Wed, 14 Oct 2020 13:40:12 +0200
Subject: 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.
---
 internal/syscallcompat/eintr.go | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

(limited to 'internal/syscallcompat')

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
+	}
 }
-- 
cgit v1.2.3