summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2019-04-17 12:56:23 -0700
committerShentubot <shentubot@google.com>2019-04-17 12:57:40 -0700
commitc8cee7108f1a1b37e89961c6dd69ccab97952c86 (patch)
tree57565d1df112795354487f636d42b9bca5a231e2 /runsc/boot
parent08d99c5fbea76ecc92038280387d24ecdf7ed814 (diff)
Use FD limit and file size limit from host
FD limit and file size limit is read from the host, instead of using hard-coded defaults, given that they effect the sandbox process. Also limit the direct cache to use no more than half if the available FDs. PiperOrigin-RevId: 244050323 Change-Id: I787ad0fdf07c49d589e51aebfeae477324fe26e6
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/fs.go19
-rw-r--r--runsc/boot/limits.go77
-rw-r--r--runsc/boot/loader.go4
3 files changed, 97 insertions, 3 deletions
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go
index 8dfb6dce6..761142d98 100644
--- a/runsc/boot/fs.go
+++ b/runsc/boot/fs.go
@@ -20,10 +20,10 @@ import (
"path/filepath"
"strconv"
"strings"
+ "syscall"
// Include filesystem types that OCI spec might mount.
_ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/dev"
- _ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/gofer"
_ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/host"
_ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/proc"
_ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/sys"
@@ -38,6 +38,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/log"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/gofer"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs"
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/runsc/specutils"
@@ -81,6 +82,22 @@ func (f *fdDispenser) empty() bool {
return len(f.fds) == 0
}
+func adjustDirentCache(k *kernel.Kernel) error {
+ var hl syscall.Rlimit
+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &hl); err != nil {
+ return fmt.Errorf("getting RLIMIT_NOFILE: %v", err)
+ }
+ if int64(hl.Cur) != syscall.RLIM_INFINITY {
+ newSize := hl.Cur / 2
+ if newSize < gofer.DefaultDirentCacheSize {
+ log.Infof("Setting gofer dirent cache size to %d", newSize)
+ gofer.DefaultDirentCacheSize = newSize
+ k.DirentCacheLimiter = fs.NewDirentCacheLimiter(newSize)
+ }
+ }
+ return nil
+}
+
// setupRootContainerFS creates a mount namespace containing the root filesystem
// and all mounts. 'rootCtx' is used to walk directories to find mount points.
// 'setMountNS' is called after namespace is created. It must set the mount NS
diff --git a/runsc/boot/limits.go b/runsc/boot/limits.go
index e3e716bf9..32e62cdf7 100644
--- a/runsc/boot/limits.go
+++ b/runsc/boot/limits.go
@@ -16,8 +16,11 @@ package boot
import (
"fmt"
+ "sync"
+ "syscall"
specs "github.com/opencontainers/runtime-spec/specs-go"
+ "gvisor.googlesource.com/gvisor/pkg/log"
"gvisor.googlesource.com/gvisor/pkg/sentry/limits"
)
@@ -41,10 +44,43 @@ var fromLinuxResource = map[string]limits.LimitType{
"RLIMIT_STACK": limits.Stack,
}
-func createLimitSet(spec *specs.Spec) (*limits.LimitSet, error) {
+func findName(lt limits.LimitType) string {
+ for k, v := range fromLinuxResource {
+ if v == lt {
+ return k
+ }
+ }
+ return "unknown"
+}
+
+var defaults defs
+
+type defs struct {
+ mu sync.Mutex
+ set *limits.LimitSet
+ err error
+}
+
+func (d *defs) get() (*limits.LimitSet, error) {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+
+ if d.err != nil {
+ return nil, d.err
+ }
+ if d.set == nil {
+ if err := d.initDefaults(); err != nil {
+ d.err = err
+ return nil, err
+ }
+ }
+ return d.set, nil
+}
+
+func (d *defs) initDefaults() error {
ls, err := limits.NewLinuxLimitSet()
if err != nil {
- return nil, err
+ return err
}
// Set default limits based on what containers get by default, ex:
@@ -66,6 +102,43 @@ func createLimitSet(spec *specs.Spec) (*limits.LimitSet, error) {
ls.SetUnchecked(limits.SignalsPending, limits.Limit{Cur: 0, Max: 0})
ls.SetUnchecked(limits.Stack, limits.Limit{Cur: 8388608, Max: limits.Infinity})
+ // Read host limits that directly affect the sandbox and adjust the defaults
+ // based on them.
+ for _, res := range []int{syscall.RLIMIT_FSIZE, syscall.RLIMIT_NOFILE} {
+ var hl syscall.Rlimit
+ if err := syscall.Getrlimit(res, &hl); err != nil {
+ return err
+ }
+
+ lt, ok := limits.FromLinuxResource[res]
+ if !ok {
+ return fmt.Errorf("unknown rlimit type %v", res)
+ }
+ hostLimit := limits.Limit{
+ Cur: limits.FromLinux(hl.Cur),
+ Max: limits.FromLinux(hl.Max),
+ }
+
+ defaultLimit := ls.Get(lt)
+ if hostLimit.Cur != limits.Infinity && hostLimit.Cur < defaultLimit.Cur {
+ log.Warningf("Host limit is lower than recommended, resource: %q, host: %d, recommended: %d", findName(lt), hostLimit.Cur, defaultLimit.Cur)
+ }
+ if hostLimit.Cur != defaultLimit.Cur || hostLimit.Max != defaultLimit.Max {
+ log.Infof("Setting limit from host, resource: %q {soft: %d, hard: %d}", findName(lt), hostLimit.Cur, hostLimit.Max)
+ ls.SetUnchecked(lt, hostLimit)
+ }
+ }
+
+ d.set = ls
+ return nil
+}
+
+func createLimitSet(spec *specs.Spec) (*limits.LimitSet, error) {
+ ls, err := defaults.get()
+ if err != nil {
+ return nil, err
+ }
+
// Then apply overwrites on top of defaults.
for _, rl := range spec.Process.Rlimits {
lt, ok := fromLinuxResource[rl.Type]
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 56cb137f0..88a834aa5 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -274,6 +274,10 @@ func New(args Args) (*Loader, error) {
return nil, fmt.Errorf("initializing kernel: %v", err)
}
+ if err := adjustDirentCache(k); err != nil {
+ return nil, err
+ }
+
// Turn on packet logging if enabled.
if args.Conf.LogPackets {
log.Infof("Packet logging enabled")