From b5747c5318b3af1bb596a1dd5d0b30d979e08c94 Mon Sep 17 00:00:00 2001 From: Andrew Dunham Date: Wed, 8 Jul 2020 07:30:30 -0700 Subject: [PATCH] cgroup: retry file writes on EINTR errors After deploying a version of gvisor built with Go 1.14, we're seeing errors setting up cgroups (we manually run `runsc` via `runsc run`, which creates the cgroup). This turns out to be a known issue with Go: https://github.com/golang/go/issues/38033. Given that the [fix won't be backported](https://github.com/golang/go/issues/39026#issuecomment-627589315), we should retry writes that may fail with EINTR. This is also what runc does: https://github.com/opencontainers/runc/pull/2258 FUTURE_COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/3102 from stripe:andrew/cgroup-eintr 079123b363e4ec5577f656001e77c1dcf057bbcb PiperOrigin-RevId: 320183771 --- runsc/cgroup/cgroup.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/runsc/cgroup/cgroup.go b/runsc/cgroup/cgroup.go index e5cc9d622a..8fbc3887a4 100644 --- a/runsc/cgroup/cgroup.go +++ b/runsc/cgroup/cgroup.go @@ -92,7 +92,17 @@ func setOptionalValueUint16(path, name string, val *uint16) error { func setValue(path, name, data string) error { fullpath := filepath.Join(path, name) - return ioutil.WriteFile(fullpath, []byte(data), 0700) + + // Retry writes on EINTR; see: + // https://github.com/golang/go/issues/38033 + for { + err := ioutil.WriteFile(fullpath, []byte(data), 0700) + if err == nil { + return nil + } else if !errors.Is(err, syscall.EINTR) { + return err + } + } } func getValue(path, name string) (string, error) { @@ -132,8 +142,16 @@ func fillFromAncestor(path string) (string, error) { if err != nil { return "", err } - if err := ioutil.WriteFile(path, []byte(val), 0700); err != nil { - return "", err + + // Retry writes on EINTR; see: + // https://github.com/golang/go/issues/38033 + for { + err := ioutil.WriteFile(path, []byte(val), 0700) + if err == nil { + break + } else if !errors.Is(err, syscall.EINTR) { + return "", err + } } return val, nil }