Skip to content

Commit

Permalink
Fix kmem limit set
Browse files Browse the repository at this point in the history
Currently we can't start container with kmem limit, because we
set kmem limit after processes joined to cgroup, we'll get device
busy error in this case.

Fix it by moving set before join.

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
  • Loading branch information
hqhq committed Jun 18, 2015
1 parent ca3ab4b commit 39279b1
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 13 deletions.
21 changes: 15 additions & 6 deletions cgroups/fs/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,29 @@ type MemoryGroup struct {
}

func (s *MemoryGroup) Apply(d *data) error {
dir, err := d.join("memory")
path, err := d.path("memory")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
return err
}
if err := s.Set(path, d.c); err != nil {
return err
}

// We need to join memory cgroup after set memory limits, because
// kmem.limit_in_bytes can only be set when the cgroup is empty.
_, err = d.join("memory")
if err != nil {
return err
}
defer func() {
if err != nil {
os.RemoveAll(dir)
os.RemoveAll(path)
}
}()

if err := s.Set(dir, d.c); err != nil {
return err
}

return nil
}

Expand Down
36 changes: 30 additions & 6 deletions cgroups/systemd/apply_systemd.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,16 @@ func (m *Manager) Apply(pid int) error {
newProp("BlockIOWeight", uint64(c.BlkioWeight)))
}

// We need to set kernel memory before processes join cgroup because
// kmem.limit_in_bytes can only be set when the cgroup is empty.
// And swap memory limit needs to be set after memory limit, only
// memory limit is handled by systemd, so it's kind of ugly here.
if c.KernelMemory > 0 {
if err := setKernelMemory(c); err != nil {
return err
}
}

if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
return err
}
Expand Down Expand Up @@ -462,26 +472,40 @@ func joinDevices(c *configs.Cgroup, pid int) error {
return devices.Set(path, c)
}

func joinMemory(c *configs.Cgroup, pid int) error {
func setKernelMemory(c *configs.Cgroup) error {
path, err := getSubsystemPath(c, "memory")
if err != nil && !cgroups.IsNotFound(err) {
return err
}

// -1 disables memoryswap
if c.MemorySwap > 0 {
err = writeFile(path, "memory.memsw.limit_in_bytes", strconv.FormatInt(c.MemorySwap, 10))
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
return err
}

if c.KernelMemory > 0 {
err = writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(c.KernelMemory, 10))
if err != nil {
return err
}
}

if c.KernelMemory > 0 {
err = writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(c.KernelMemory, 10))
return nil
}

func joinMemory(c *configs.Cgroup, pid int) error {
path, err := getSubsystemPath(c, "memory")
if err != nil && !cgroups.IsNotFound(err) {
return err
}

// -1 disables memoryswap
if c.MemorySwap > 0 {
err = writeFile(path, "memory.memsw.limit_in_bytes", strconv.FormatInt(c.MemorySwap, 10))
if err != nil {
return err
}
}

if c.MemorySwappiness >= 0 && c.MemorySwappiness <= 100 {
err = writeFile(path, "memory.swappiness", strconv.FormatInt(c.MemorySwappiness, 10))
if err != nil {
Expand Down
33 changes: 32 additions & 1 deletion integration/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ func TestCpuShares(t *testing.T) {
testCpuShares(t, false)
}

func TestSystemdCpuShares(t *testing.T) {
func TestCpuSharesSystemd(t *testing.T) {
if !systemd.UseSystemd() {
t.Skip("Systemd is unsupported")
}
Expand All @@ -524,6 +524,37 @@ func testCpuShares(t *testing.T, systemd bool) {
}
}

func TestRunWithKernelMemory(t *testing.T) {
testRunWithKernelMemory(t, false)
}

func TestRunWithKernelMemorySystemd(t *testing.T) {
if !systemd.UseSystemd() {
t.Skip("Systemd is unsupported")
}
testRunWithKernelMemory(t, true)
}

func testRunWithKernelMemory(t *testing.T, systemd bool) {
if testing.Short() {
return
}
rootfs, err := newRootfs()
ok(t, err)
defer remove(rootfs)

config := newTemplateConfig(rootfs)
if systemd {
config.Cgroups.Slice = "system.slice"
}
config.Cgroups.KernelMemory = 52428800

_, _, err = runContainer(config, "", "ps")
if err != nil {
t.Fatalf("runContainer failed with kernel memory limit: %v", err)
}
}

func TestContainerState(t *testing.T) {
if testing.Short() {
return
Expand Down

0 comments on commit 39279b1

Please sign in to comment.