diff options
author | Giuseppe Scrivano <gscrivan@redhat.com> | 2022-01-14 13:15:08 +0100 |
---|---|---|
committer | Giuseppe Scrivano <gscrivan@redhat.com> | 2022-01-24 16:58:05 +0100 |
commit | e252b3b4f294745ca8ac6d1c1850de2e7f1365c7 (patch) | |
tree | cc67df1972a34392a2f513d5ad41aaa63d1a59ba /libpod/container_exec.go | |
parent | 75e6994d4edc712a281aaa46574ed90ecd19ba49 (diff) | |
download | podman-e252b3b4f294745ca8ac6d1c1850de2e7f1365c7.tar.gz podman-e252b3b4f294745ca8ac6d1c1850de2e7f1365c7.tar.bz2 podman-e252b3b4f294745ca8ac6d1c1850de2e7f1365c7.zip |
exec: retry rm -rf on ENOTEMPTY and EBUSY
when running on NFS, a RemoveAll could cause EBUSY because of some
unlinked files that are still kept open and "silly renamed" to
.nfs$ID.
This is only half of the fix, as conmon needs to be fixed too.
Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2040379
Related: https://github.com/containers/conmon/pull/319
[NO NEW TESTS NEEDED] as it requires NFS as the underlying storage.
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Diffstat (limited to 'libpod/container_exec.go')
-rw-r--r-- | libpod/container_exec.go | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/libpod/container_exec.go b/libpod/container_exec.go index 7d4e28d5d..d1c190905 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -14,6 +14,7 @@ import ( "github.com/containers/storage/pkg/stringid" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) // ExecConfig contains the configuration of an exec session @@ -774,13 +775,40 @@ func (c *Container) Exec(config *ExecConfig, streams *define.AttachStreams, resi return exitCode, nil } -// cleanup an exec session after its done -func (c *Container) cleanupExecBundle(sessionID string) error { - if err := os.RemoveAll(c.execBundlePath(sessionID)); err != nil && !os.IsNotExist(err) { - return err +// cleanupExecBundle cleanups an exec session after its done +// Please be careful when using this function since it might temporarily unlock +// the container when os.RemoveAll($bundlePath) fails with ENOTEMPTY or EBUSY +// errors. +func (c *Container) cleanupExecBundle(sessionID string) (Err error) { + path := c.execBundlePath(sessionID) + for attempts := 0; attempts < 50; attempts++ { + Err = os.RemoveAll(path) + if Err == nil || os.IsNotExist(Err) { + return nil + } + if pathErr, ok := Err.(*os.PathError); ok { + Err = pathErr.Err + if errors.Cause(Err) == unix.ENOTEMPTY || errors.Cause(Err) == unix.EBUSY { + // give other processes a chance to use the container + if !c.batched { + if err := c.save(); err != nil { + return err + } + c.lock.Unlock() + } + time.Sleep(time.Millisecond * 100) + if !c.batched { + c.lock.Lock() + if err := c.syncContainer(); err != nil { + return err + } + } + continue + } + } + return } - - return nil + return } // the path to a containers exec session bundle |