Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions libcontainer/configs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ type Config struct {
// If Rlimits are not set, the container will inherit rlimits from the parent process
Rlimits []Rlimit `json:"rlimits"`

// OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores
// for a process. Valid values are between the range [-1000, '1000'], where processes with
// higher scores are preferred for being killed.
// More information about kernel oom score calculation here: https://lwn.net/Articles/317814/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think could point to https://www.kernel.org/doc/Documentation/filesystems/proc.txt instead as oom_score_adj can't be found on the lwn page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. Updated!

OomScoreAdj int `json:"oom_score_adj"`

// AdditionalGroups specifies the gids that should be added to supplementary groups
// in addition to those that the user belongs to.
AdditionalGroups []string `json:"additional_groups"`
Expand Down
7 changes: 7 additions & 0 deletions libcontainer/init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package libcontainer
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"syscall"

Expand Down Expand Up @@ -238,6 +240,11 @@ func setupRlimits(config *configs.Config) error {
return nil
}

func setOomScoreAdj(oomScoreAdj int) error {
path := "/proc/self/oom_score_adj"
return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0700)
}

// killCgroupProcesses freezes then iterates over all the processes inside the
// manager's cgroups sending a SIGKILL to each process then waiting for them to
// exit.
Expand Down
42 changes: 42 additions & 0 deletions libcontainer/integration/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -878,3 +878,45 @@ func TestMountCgroupRW(t *testing.T) {
}
}
}

func TestOomScoreAdj(t *testing.T) {
if testing.Short() {
return
}
root, err := newTestRoot()
ok(t, err)
defer os.RemoveAll(root)

rootfs, err := newRootfs()
ok(t, err)
defer remove(rootfs)

config := newTemplateConfig(rootfs)
config.OomScoreAdj = 200

factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
ok(t, err)

container, err := factory.Create("test", config)
ok(t, err)
defer container.Destroy()

var stdout bytes.Buffer
pconfig := libcontainer.Process{
Args: []string{"sh", "-c", "cat /proc/self/oom_score_adj"},
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
}
err = container.Start(&pconfig)
ok(t, err)

// Wait for process
waitProcess(&pconfig, t)
outputOomScoreAdj := strings.TrimSpace(string(stdout.Bytes()))

// Check that the oom_score_adj matches the value that was set as part of config.
if outputOomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
t.Fatalf("Expected oom_score_adj %d; got %q", config.OomScoreAdj, outputOomScoreAdj)
}
}
47 changes: 47 additions & 0 deletions libcontainer/integration/execin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"io"
"os"
"strconv"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -332,3 +333,49 @@ func TestExecinPassExtraFiles(t *testing.T) {
t.Fatalf("expected second pipe to receive '2', got '%s'", out2)
}
}

func TestExecInOomScoreAdj(t *testing.T) {
if testing.Short() {
return
}
rootfs, err := newRootfs()
ok(t, err)
defer remove(rootfs)
config := newTemplateConfig(rootfs)
config.OomScoreAdj = 200
container, err := newContainer(config)
ok(t, err)
defer container.Destroy()

stdinR, stdinW, err := os.Pipe()
ok(t, err)
process := &libcontainer.Process{
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
}
err = container.Start(process)
stdinR.Close()
defer stdinW.Close()
ok(t, err)

buffers := newStdBuffers()
ps := &libcontainer.Process{
Args: []string{"/bin/sh", "-c", "cat /proc/self/oom_score_adj"},
Env: standardEnvironment,
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
}
err = container.Start(ps)
ok(t, err)
waitProcess(ps, t)

stdinW.Close()
waitProcess(process, t)

out := buffers.Stdout.String()
if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj)
}
}
3 changes: 3 additions & 0 deletions libcontainer/setns_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ func (l *linuxSetnsInit) Init() error {
if err := setupRlimits(l.config.Config); err != nil {
return err
}
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
return err
}
if l.config.Config.Seccomp != nil {
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions libcontainer/standard_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func (l *linuxStandardInit) Init() error {
if err := setupRlimits(l.config.Config); err != nil {
return err
}
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
return err
}

label.Init()
// InitializeMountNamespace() can be executed only for a new mount namespace
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
Expand Down