Skip to content

Commit

Permalink
Merge pull request #4290 from kolyshkin/rlimit-rework
Browse files Browse the repository at this point in the history
Rlimit cache rework for Go 1.23+
  • Loading branch information
lifubang authored Jun 1, 2024
2 parents ba4b52d + 584afc6 commit 854c4af
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 23 deletions.
16 changes: 9 additions & 7 deletions libcontainer/init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"runtime/debug"
"strconv"
"strings"
"syscall"

"github.com/containerd/console"
"github.com/moby/sys/user"
Expand Down Expand Up @@ -225,9 +226,7 @@ func containerInit(t initType, config *initConfig, pipe *syncSocket, consoleSock

// Clean the RLIMIT_NOFILE cache in go runtime.
// Issue: https://github.com/opencontainers/runc/issues/4195
if containsRlimit(config.Rlimits, unix.RLIMIT_NOFILE) {
system.ClearRlimitNofileCache()
}
maybeClearRlimitNofileCache(config.Rlimits)

switch t {
case initSetns:
Expand Down Expand Up @@ -655,13 +654,16 @@ func setupRoute(config *configs.Config) error {
return nil
}

func containsRlimit(limits []configs.Rlimit, resource int) bool {
func maybeClearRlimitNofileCache(limits []configs.Rlimit) {
for _, rlimit := range limits {
if rlimit.Type == resource {
return true
if rlimit.Type == syscall.RLIMIT_NOFILE {
system.ClearRlimitNofileCache(&syscall.Rlimit{
Cur: rlimit.Soft,
Max: rlimit.Hard,
})
return
}
}
return false
}

func setupRlimits(limits []configs.Rlimit, pid int) error {
Expand Down
16 changes: 0 additions & 16 deletions libcontainer/system/linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,13 @@ import (
"io"
"os"
"strconv"
"sync/atomic"
"syscall"
"unsafe"

"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile
var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit]

// ClearRlimitNofileCache is to clear go runtime's nofile rlimit cache.
func ClearRlimitNofileCache() {
// As reported in issue #4195, the new version of go runtime(since 1.19)
// will cache rlimit-nofile. Before executing execve, the rlimit-nofile
// of the process will be restored with the cache. In runc, this will
// cause the rlimit-nofile setting by the parent process for the container
// to become invalid. It can be solved by clearing this cache. But
// unfortunately, go stdlib doesn't provide such function, so we need to
// link to the private var `origRlimitNofile` in package syscall to hack.
syscallOrigRlimitNofile.Store(nil)
}

type ParentDeathSignal int

func (p ParentDeathSignal) Restore() error {
Expand Down
15 changes: 15 additions & 0 deletions libcontainer/system/rlimit_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build go1.23

package system

import (
"syscall"
)

// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. The argument
// is process RLIMIT_NOFILE values. Relies on go.dev/cl/588076.
func ClearRlimitNofileCache(lim *syscall.Rlimit) {
// Ignore the return values since we only need to clean the cache,
// the limit is going to be set via unix.Prlimit elsewhere.
_ = syscall.Setrlimit(syscall.RLIMIT_NOFILE, lim)
}
27 changes: 27 additions & 0 deletions libcontainer/system/rlimit_linux_go122.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build !go1.23

// TODO: remove this file once go 1.22 is no longer supported.

package system

import (
"sync/atomic"
"syscall"
_ "unsafe" // Needed for go:linkname to work.
)

//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile
var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit]

// ClearRlimitNofileCache clears go runtime's nofile rlimit cache.
// The argument is process RLIMIT_NOFILE values.
func ClearRlimitNofileCache(_ *syscall.Rlimit) {
// As reported in issue #4195, the new version of go runtime(since 1.19)
// will cache rlimit-nofile. Before executing execve, the rlimit-nofile
// of the process will be restored with the cache. In runc, this will
// cause the rlimit-nofile setting by the parent process for the container
// to become invalid. It can be solved by clearing this cache. But
// unfortunately, go stdlib doesn't provide such function, so we need to
// link to the private var `origRlimitNofile` in package syscall to hack.
syscallOrigRlimitNofile.Store(nil)
}

0 comments on commit 854c4af

Please sign in to comment.