diff options
author | Jakob Unterwurzacher | 2020-10-14 00:35:16 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2020-10-14 00:35:16 +0200 |
commit | af4c1fb7a3f428ff704af22294ad955d05ed41dd (patch) | |
tree | 66bdf7480ff1dd82bf2653c2070871762f24d742 /internal/syscallcompat/eintr.go | |
parent | 803fdf410bb57d34ef09357ec4924646978c20b5 (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.go | 48 |
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 +} |