Skip to content

Commit 854c4af

Browse files
authored
Merge pull request #4290 from kolyshkin/rlimit-rework
Rlimit cache rework for Go 1.23+
2 parents ba4b52d + 584afc6 commit 854c4af

File tree

4 files changed

+51
-23
lines changed

4 files changed

+51
-23
lines changed

libcontainer/init_linux.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"runtime/debug"
1313
"strconv"
1414
"strings"
15+
"syscall"
1516

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

226227
// Clean the RLIMIT_NOFILE cache in go runtime.
227228
// Issue: https://github.com/opencontainers/runc/issues/4195
228-
if containsRlimit(config.Rlimits, unix.RLIMIT_NOFILE) {
229-
system.ClearRlimitNofileCache()
230-
}
229+
maybeClearRlimitNofileCache(config.Rlimits)
231230

232231
switch t {
233232
case initSetns:
@@ -655,13 +654,16 @@ func setupRoute(config *configs.Config) error {
655654
return nil
656655
}
657656

658-
func containsRlimit(limits []configs.Rlimit, resource int) bool {
657+
func maybeClearRlimitNofileCache(limits []configs.Rlimit) {
659658
for _, rlimit := range limits {
660-
if rlimit.Type == resource {
661-
return true
659+
if rlimit.Type == syscall.RLIMIT_NOFILE {
660+
system.ClearRlimitNofileCache(&syscall.Rlimit{
661+
Cur: rlimit.Soft,
662+
Max: rlimit.Hard,
663+
})
664+
return
662665
}
663666
}
664-
return false
665667
}
666668

667669
func setupRlimits(limits []configs.Rlimit, pid int) error {

libcontainer/system/linux.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,13 @@ import (
88
"io"
99
"os"
1010
"strconv"
11-
"sync/atomic"
1211
"syscall"
1312
"unsafe"
1413

1514
"github.com/sirupsen/logrus"
1615
"golang.org/x/sys/unix"
1716
)
1817

19-
//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile
20-
var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit]
21-
22-
// ClearRlimitNofileCache is to clear go runtime's nofile rlimit cache.
23-
func ClearRlimitNofileCache() {
24-
// As reported in issue #4195, the new version of go runtime(since 1.19)
25-
// will cache rlimit-nofile. Before executing execve, the rlimit-nofile
26-
// of the process will be restored with the cache. In runc, this will
27-
// cause the rlimit-nofile setting by the parent process for the container
28-
// to become invalid. It can be solved by clearing this cache. But
29-
// unfortunately, go stdlib doesn't provide such function, so we need to
30-
// link to the private var `origRlimitNofile` in package syscall to hack.
31-
syscallOrigRlimitNofile.Store(nil)
32-
}
33-
3418
type ParentDeathSignal int
3519

3620
func (p ParentDeathSignal) Restore() error {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build go1.23
2+
3+
package system
4+
5+
import (
6+
"syscall"
7+
)
8+
9+
// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. The argument
10+
// is process RLIMIT_NOFILE values. Relies on go.dev/cl/588076.
11+
func ClearRlimitNofileCache(lim *syscall.Rlimit) {
12+
// Ignore the return values since we only need to clean the cache,
13+
// the limit is going to be set via unix.Prlimit elsewhere.
14+
_ = syscall.Setrlimit(syscall.RLIMIT_NOFILE, lim)
15+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//go:build !go1.23
2+
3+
// TODO: remove this file once go 1.22 is no longer supported.
4+
5+
package system
6+
7+
import (
8+
"sync/atomic"
9+
"syscall"
10+
_ "unsafe" // Needed for go:linkname to work.
11+
)
12+
13+
//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile
14+
var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit]
15+
16+
// ClearRlimitNofileCache clears go runtime's nofile rlimit cache.
17+
// The argument is process RLIMIT_NOFILE values.
18+
func ClearRlimitNofileCache(_ *syscall.Rlimit) {
19+
// As reported in issue #4195, the new version of go runtime(since 1.19)
20+
// will cache rlimit-nofile. Before executing execve, the rlimit-nofile
21+
// of the process will be restored with the cache. In runc, this will
22+
// cause the rlimit-nofile setting by the parent process for the container
23+
// to become invalid. It can be solved by clearing this cache. But
24+
// unfortunately, go stdlib doesn't provide such function, so we need to
25+
// link to the private var `origRlimitNofile` in package syscall to hack.
26+
syscallOrigRlimitNofile.Store(nil)
27+
}

0 commit comments

Comments
 (0)