Skip to content

Commit cc232c4

Browse files
committed
Adding oom_score_adj as a container config param.
Signed-off-by: Vishnu Kannan <vishnuk@google.com>
1 parent b1e7041 commit cc232c4

File tree

6 files changed

+109
-0
lines changed

6 files changed

+109
-0
lines changed

libcontainer/configs/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ type Config struct {
127127
// If Rlimits are not set, the container will inherit rlimits from the parent process
128128
Rlimits []Rlimit `json:"rlimits"`
129129

130+
// OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores
131+
// for a process. Valid values are between the range [-1000, '1000'], where processes with
132+
// higher scores are preferred for being killed.
133+
// More information about kernel oom score calculation here: https://lwn.net/Articles/317814/
134+
OomScoreAdj int `json:"oom_score_adj"`
135+
130136
// AdditionalGroups specifies the gids that should be added to supplementary groups
131137
// in addition to those that the user belongs to.
132138
AdditionalGroups []string `json:"additional_groups"`

libcontainer/init_linux.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ package libcontainer
55
import (
66
"encoding/json"
77
"fmt"
8+
"io/ioutil"
89
"os"
10+
"strconv"
911
"strings"
1012
"syscall"
1113

@@ -238,6 +240,11 @@ func setupRlimits(config *configs.Config) error {
238240
return nil
239241
}
240242

243+
func setOomScoreAdj(oomScoreAdj int) error {
244+
path := "/proc/self/oom_score_adj"
245+
return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0700)
246+
}
247+
241248
// killCgroupProcesses freezes then iterates over all the processes inside the
242249
// manager's cgroups sending a SIGKILL to each process then waiting for them to
243250
// exit.

libcontainer/integration/exec_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,3 +878,45 @@ func TestMountCgroupRW(t *testing.T) {
878878
}
879879
}
880880
}
881+
882+
func TestOomScoreAdj(t *testing.T) {
883+
if testing.Short() {
884+
return
885+
}
886+
root, err := newTestRoot()
887+
ok(t, err)
888+
defer os.RemoveAll(root)
889+
890+
rootfs, err := newRootfs()
891+
ok(t, err)
892+
defer remove(rootfs)
893+
894+
config := newTemplateConfig(rootfs)
895+
config.OomScoreAdj = 200
896+
897+
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
898+
ok(t, err)
899+
900+
container, err := factory.Create("test", config)
901+
ok(t, err)
902+
defer container.Destroy()
903+
904+
var stdout bytes.Buffer
905+
pconfig := libcontainer.Process{
906+
Args: []string{"sh", "-c", "cat /proc/self/oom_score_adj"},
907+
Env: standardEnvironment,
908+
Stdin: nil,
909+
Stdout: &stdout,
910+
}
911+
err = container.Start(&pconfig)
912+
ok(t, err)
913+
914+
// Wait for process
915+
waitProcess(&pconfig, t)
916+
outputOomScoreAdj := strings.TrimSpace(string(stdout.Bytes()))
917+
918+
// Check that the oom_score_adj matches the value that was set as part of config.
919+
if outputOomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
920+
t.Fatalf("Expected oom_score_adj %d; got %q", config.OomScoreAdj, outputOomScoreAdj)
921+
}
922+
}

libcontainer/integration/execin_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"io"
66
"os"
7+
"strconv"
78
"strings"
89
"testing"
910
"time"
@@ -332,3 +333,49 @@ func TestExecinPassExtraFiles(t *testing.T) {
332333
t.Fatalf("expected second pipe to receive '2', got '%s'", out2)
333334
}
334335
}
336+
337+
func TestExecInOomScoreAdj(t *testing.T) {
338+
if testing.Short() {
339+
return
340+
}
341+
rootfs, err := newRootfs()
342+
ok(t, err)
343+
defer remove(rootfs)
344+
config := newTemplateConfig(rootfs)
345+
config.OomScoreAdj = 200
346+
container, err := newContainer(config)
347+
ok(t, err)
348+
defer container.Destroy()
349+
350+
stdinR, stdinW, err := os.Pipe()
351+
ok(t, err)
352+
process := &libcontainer.Process{
353+
Args: []string{"cat"},
354+
Env: standardEnvironment,
355+
Stdin: stdinR,
356+
}
357+
err = container.Start(process)
358+
stdinR.Close()
359+
defer stdinW.Close()
360+
ok(t, err)
361+
362+
buffers := newStdBuffers()
363+
ps := &libcontainer.Process{
364+
Args: []string{"/bin/sh", "-c", "cat /proc/self/oom_score_adj"},
365+
Env: standardEnvironment,
366+
Stdin: buffers.Stdin,
367+
Stdout: buffers.Stdout,
368+
Stderr: buffers.Stderr,
369+
}
370+
err = container.Start(ps)
371+
ok(t, err)
372+
waitProcess(ps, t)
373+
374+
stdinW.Close()
375+
waitProcess(process, t)
376+
377+
out := buffers.Stdout.String()
378+
if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
379+
t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj)
380+
}
381+
}

libcontainer/setns_init_linux.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ func (l *linuxSetnsInit) Init() error {
2121
if err := setupRlimits(l.config.Config); err != nil {
2222
return err
2323
}
24+
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
25+
return err
26+
}
2427
if l.config.Config.Seccomp != nil {
2528
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
2629
return err

libcontainer/standard_init_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ func (l *linuxStandardInit) Init() error {
4747
if err := setupRlimits(l.config.Config); err != nil {
4848
return err
4949
}
50+
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
51+
return err
52+
}
53+
5054
label.Init()
5155
// InitializeMountNamespace() can be executed only for a new mount namespace
5256
if l.config.Config.Namespaces.Contains(configs.NEWNS) {

0 commit comments

Comments
 (0)