Skip to content

Commit 8dd3d63

Browse files
committed
Look at modify time to check if kmem limits are initialized.
Signed-off-by: Vishnu kannan <[email protected]>
1 parent 9d7831e commit 8dd3d63

File tree

2 files changed

+42
-26
lines changed

2 files changed

+42
-26
lines changed

libcontainer/cgroups/fs/memory.go

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ package fs
55
import (
66
"bufio"
77
"fmt"
8-
"math"
98
"os"
109
"path/filepath"
1110
"strconv"
1211
"strings"
12+
"time"
1313

1414
"github.com/opencontainers/runc/libcontainer/cgroups"
1515
"github.com/opencontainers/runc/libcontainer/configs"
16-
"github.com/opencontainers/runc/libcontainer/system"
1716
)
1817

1918
type MemoryGroup struct {
@@ -28,53 +27,65 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
2827
if err != nil && !cgroups.IsNotFound(err) {
2928
return err
3029
}
31-
if memoryAssigned(d.config) {
32-
if path != "" {
33-
if err := os.MkdirAll(path, 0755); err != nil {
34-
return err
35-
}
36-
}
37-
// We have to set kernel memory here, as we can't change it once
38-
// processes have been attached to the cgroup.
39-
if err := s.SetKernelMemory(path, d.config); err != nil {
40-
return err
41-
}
30+
// reset error.
31+
err = nil
32+
if path == "" {
33+
// Invalid input.
34+
return fmt.Errorf("invalid path for memory cgroups: %+v", d)
4235
}
43-
4436
defer func() {
4537
if err != nil {
4638
os.RemoveAll(path)
4739
}
4840
}()
49-
41+
if !cgroups.PathExists(path) {
42+
if err = os.MkdirAll(path, 0755); err != nil {
43+
return err
44+
}
45+
}
46+
if memoryAssigned(d.config) {
47+
// We have to set kernel memory here, as we can't change it once
48+
// processes have been attached to the cgroup.
49+
if err = s.SetKernelMemory(path, d.config); err != nil {
50+
return err
51+
}
52+
}
5053
// We need to join memory cgroup after set memory limits, because
5154
// kmem.limit_in_bytes can only be set when the cgroup is empty.
52-
_, err = d.join("memory")
53-
if err != nil && !cgroups.IsNotFound(err) {
55+
if _, jerr := d.join("memory"); jerr != nil && !cgroups.IsNotFound(jerr) {
56+
err = jerr
5457
return err
5558
}
5659
return nil
5760
}
5861

62+
func getModifyTime(path string) (time.Time, error) {
63+
stat, err := os.Stat(path)
64+
if err != nil {
65+
return time.Time{}, fmt.Errorf("failed to get memory cgroups creation time: %v", err)
66+
}
67+
return stat.ModTime(), nil
68+
}
69+
5970
func (s *MemoryGroup) SetKernelMemory(path string, cgroup *configs.Cgroup) error {
6071
// This has to be done separately because it has special
6172
// constraints (it can only be initialized before setting up a
6273
// hierarchy or adding a task to the cgroups. However, if
6374
// sucessfully initialized, it can be updated anytime afterwards)
6475
if cgroup.Resources.KernelMemory != 0 {
65-
kmemInitialized := false
6676
// Is kmem.limit_in_bytes already set?
67-
kmemValue, err := getCgroupParamUint(path, "memory.kmem.limit_in_bytes")
77+
// memory.kmem.max_usage_in_bytes is a read-only file. Use it to get cgroups creation time.
78+
kmemCreationTime, err := getModifyTime(filepath.Join(path, "memory.kmem.max_usage_in_bytes"))
6879
if err != nil {
6980
return err
7081
}
71-
switch system.GetLongBit() {
72-
case 32:
73-
kmemInitialized = uint32(kmemValue) != uint32(math.MaxUint32)
74-
case 64:
75-
kmemInitialized = kmemValue != uint64(math.MaxUint64)
82+
kmemLimitsUpdateTime, err := getModifyTime(filepath.Join(path, "memory.kmem.limit_in_bytes"))
83+
if err != nil {
84+
return err
7685
}
77-
86+
// kmem.limit_in_bytes has already been set if its update time is after that of creation time.
87+
// We use `!=` op instead of `>` because updates are losing precision compared to creation.
88+
kmemInitialized := !kmemLimitsUpdateTime.Equal(kmemCreationTime)
7889
if !kmemInitialized {
7990
// If there's already tasks in the cgroup, we can't change the limit either
8091
tasks, err := getCgroupParamString(path, "tasks")
@@ -85,7 +96,6 @@ func (s *MemoryGroup) SetKernelMemory(path string, cgroup *configs.Cgroup) error
8596
return fmt.Errorf("cannot set kmem.limit_in_bytes after task have joined this cgroup")
8697
}
8798
}
88-
8999
if err := writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(cgroup.Resources.KernelMemory, 10)); err != nil {
90100
return err
91101
}

libcontainer/cgroups/fs/memory_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ func TestMemorySetKernelMemory(t *testing.T) {
227227
helper.writeFileContents(map[string]string{
228228
"memory.kmem.limit_in_bytes": strconv.Itoa(kernelMemoryBefore),
229229
})
230+
helper.writeFileContents(map[string]string{
231+
"memory.kmem.max_usage_in_bytes": strconv.Itoa(kernelMemoryBefore),
232+
})
233+
helper.writeFileContents(map[string]string{
234+
"tasks": "",
235+
})
230236

231237
helper.CgroupData.config.Resources.KernelMemory = kernelMemoryAfter
232238
memory := &MemoryGroup{}

0 commit comments

Comments
 (0)