summaryrefslogtreecommitdiff
path: root/internal/syscallcompat/eintr.go
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-10-14 00:35:16 +0200
committerJakob Unterwurzacher2020-10-14 00:35:16 +0200
commitaf4c1fb7a3f428ff704af22294ad955d05ed41dd (patch)
tree66bdf7480ff1dd82bf2653c2070871762f24d742 /internal/syscallcompat/eintr.go
parent803fdf410bb57d34ef09357ec4924646978c20b5 (diff)
syscallcompat: retry ops on EINTR
Retry operations that have been shown to throw EINTR errors on CIFS. Todo: Solution for this pain in the back: warning: unix.Getdents returned errno 2 in the middle of data rm: cannot remove 'linux-3.0.old3/Documentation/ABI/removed': Input/output error Progress towards fixing https://github.com/rfjakob/gocryptfs/issues/483 .
Diffstat (limited to 'internal/syscallcompat/eintr.go')
-rw-r--r--internal/syscallcompat/eintr.go48
1 files changed, 48 insertions, 0 deletions
diff --git a/internal/syscallcompat/eintr.go b/internal/syscallcompat/eintr.go
new file mode 100644
index 0000000..122af9b
--- /dev/null
+++ b/internal/syscallcompat/eintr.go
@@ -0,0 +1,48 @@
+package syscallcompat
+
+import (
+ "syscall"
+)
+
+// retryEINTR executes operation `op` and retries if it gets EINTR.
+//
+// Like ignoringEINTR() in the Go stdlib:
+// https://github.com/golang/go/blob/d2a80f3fb5b44450e0b304ac5a718f99c053d82a/src/os/file_posix.go#L243
+//
+// This is needed because CIFS throws lots of EINTR errors:
+// https://github.com/rfjakob/gocryptfs/issues/483
+func retryEINTR(op func() error) error {
+ for {
+ err := op()
+ if err != syscall.EINTR {
+ return err
+ }
+ }
+}
+
+// retryEINTR2 is like retryEINTR but for functions that return an (int, error)
+// pair like syscall.Create().
+func retryEINTR2(op func() (int, error)) (int, error) {
+ for {
+ ret, err := op()
+ if err != syscall.EINTR {
+ return ret, err
+ }
+ }
+}
+
+// Open wraps syscall.Open.
+// Retries on EINTR.
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ fd, err = retryEINTR2(func() (int, error) {
+ return syscall.Open(path, mode, perm)
+ })
+ return fd, err
+}
+
+// Close wraps syscall.Close.
+// Retries on EINTR.
+func Close(fd int) (err error) {
+ err = retryEINTR(func() error { return syscall.Close(fd) })
+ return err
+}