summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/fsimpl/proc/tasks_files.go5
-rw-r--r--pkg/sentry/usage/memory.go6
-rw-r--r--runsc/boot/loader.go1
-rw-r--r--runsc/sandbox/memory.go70
-rw-r--r--runsc/sandbox/sandbox.go14
5 files changed, 85 insertions, 11 deletions
diff --git a/pkg/sentry/fsimpl/proc/tasks_files.go b/pkg/sentry/fsimpl/proc/tasks_files.go
index 4d3a2f7e6..faec36d8d 100644
--- a/pkg/sentry/fsimpl/proc/tasks_files.go
+++ b/pkg/sentry/fsimpl/proc/tasks_files.go
@@ -262,9 +262,8 @@ var _ dynamicInode = (*meminfoData)(nil)
// Generate implements vfs.DynamicBytesSource.Generate.
func (*meminfoData) Generate(ctx context.Context, buf *bytes.Buffer) error {
- k := kernel.KernelFromContext(ctx)
- mf := k.MemoryFile()
- mf.UpdateUsage()
+ mf := kernel.KernelFromContext(ctx).MemoryFile()
+ _ = mf.UpdateUsage() // Best effort
snapshot, totalUsage := usage.MemoryAccounting.Copy()
totalSize := usage.TotalMemory(mf.TotalSize(), totalUsage)
anon := snapshot.Anonymous + snapshot.Tmpfs
diff --git a/pkg/sentry/usage/memory.go b/pkg/sentry/usage/memory.go
index e7073ec87..d9df890c4 100644
--- a/pkg/sentry/usage/memory.go
+++ b/pkg/sentry/usage/memory.go
@@ -252,9 +252,9 @@ func (m *MemoryLocked) Copy() (MemoryStats, uint64) {
return ms, m.totalLocked()
}
-// These options control how much total memory the is reported to the application.
-// They may only be set before the application starts executing, and must not
-// be modified.
+// These options control how much total memory the is reported to the
+// application. They may only be set before the application starts executing,
+// and must not be modified.
var (
// MinimumTotalMemoryBytes is the minimum reported total system memory.
MinimumTotalMemoryBytes uint64 = 2 << 30 // 2 GB
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 2f2d4df5e..28dbbcf1f 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -340,6 +340,7 @@ func New(args Args) (*Loader, error) {
if args.TotalMem > 0 {
// Adjust the total memory returned by the Sentry so that applications that
// use /proc/meminfo can make allocations based on this limit.
+ usage.MinimumTotalMemoryBytes = args.TotalMem
usage.MaximumTotalMemoryBytes = args.TotalMem
log.Infof("Setting total memory to %.2f GB", float64(args.TotalMem)/(1<<30))
}
diff --git a/runsc/sandbox/memory.go b/runsc/sandbox/memory.go
new file mode 100644
index 000000000..77b88eb89
--- /dev/null
+++ b/runsc/sandbox/memory.go
@@ -0,0 +1,70 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sandbox
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// totalSystemMemory extracts "MemTotal" from "/proc/meminfo".
+func totalSystemMemory() (uint64, error) {
+ f, err := os.Open("/proc/meminfo")
+ if err != nil {
+ return 0, err
+ }
+ defer f.Close()
+ return parseTotalSystemMemory(f)
+}
+
+func parseTotalSystemMemory(r io.Reader) (uint64, error) {
+ for scanner := bufio.NewScanner(r); scanner.Scan(); {
+ line := scanner.Text()
+ totalStr := strings.TrimPrefix(line, "MemTotal:")
+ if len(totalStr) < len(line) {
+ fields := strings.Fields(totalStr)
+ if len(fields) == 0 || len(fields) > 2 {
+ return 0, fmt.Errorf(`malformed "MemTotal": %q`, line)
+ }
+ totalStr = fields[0]
+ unit := ""
+ if len(fields) == 2 {
+ unit = fields[1]
+ }
+ mem, err := strconv.ParseUint(totalStr, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ switch unit {
+ case "":
+ // do nothing.
+ case "kB":
+ memKb := mem
+ mem = memKb * 1024
+ if mem < memKb {
+ return 0, fmt.Errorf(`"MemTotal" too large: %d`, memKb)
+ }
+ default:
+ return 0, fmt.Errorf("unknown unit %q: %q", unit, line)
+ }
+ return mem, nil
+ }
+ }
+ return 0, fmt.Errorf(`malformed "/proc/meminfo": "MemTotal" not found`)
+}
diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go
index f4a37cedc..714919139 100644
--- a/runsc/sandbox/sandbox.go
+++ b/runsc/sandbox/sandbox.go
@@ -758,6 +758,11 @@ func (s *Sandbox) createSandboxProcess(conf *config.Config, args *Args, startSyn
// shown as `exe`.
cmd.Args[0] = "runsc-sandbox"
+ mem, err := totalSystemMemory()
+ if err != nil {
+ return err
+ }
+
if s.Cgroup != nil {
cpuNum, err := s.Cgroup.NumCPU()
if err != nil {
@@ -785,16 +790,15 @@ func (s *Sandbox) createSandboxProcess(conf *config.Config, args *Args, startSyn
}
cmd.Args = append(cmd.Args, "--cpu-num", strconv.Itoa(cpuNum))
- mem, err := s.Cgroup.MemoryLimit()
+ memLimit, err := s.Cgroup.MemoryLimit()
if err != nil {
return fmt.Errorf("getting memory limit from cgroups: %v", err)
}
- // When memory limit is unset, a "large" number is returned. In that case,
- // just stick with the default.
- if mem < 0x7ffffffffffff000 {
- cmd.Args = append(cmd.Args, "--total-memory", strconv.FormatUint(mem, 10))
+ if memLimit < mem {
+ mem = memLimit
}
}
+ cmd.Args = append(cmd.Args, "--total-memory", strconv.FormatUint(mem, 10))
if args.UserLog != "" {
f, err := os.OpenFile(args.UserLog, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0664)