Browse code

Update libcontainer to aa10040b570386c1ae311c6245b

Includes mqueue label fix and cgroups improvements.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Michael Crosby authored on 2015/03/12 03:49:15
Showing 16 changed files
... ...
@@ -68,7 +68,7 @@ if [ "$1" = '--go' ]; then
68 68
 	mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
69 69
 fi
70 70
 
71
-clone git github.com/docker/libcontainer dd3cb8822352fd4acc0b8b426bd86e47e98f6853
71
+clone git github.com/docker/libcontainer aa10040b570386c1ae311c6245b9e21295b2b83a
72 72
 # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
73 73
 rm -rf src/github.com/docker/libcontainer/vendor
74 74
 eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
... ...
@@ -54,12 +54,10 @@ func getCgroupRoot() (string, error) {
54 54
 		return cgroupRoot, nil
55 55
 	}
56 56
 
57
-	// we can pick any subsystem to find the root
58
-	cpuRoot, err := cgroups.FindCgroupMountpoint("cpu")
57
+	root, err := cgroups.FindCgroupMountpointDir()
59 58
 	if err != nil {
60 59
 		return "", err
61 60
 	}
62
-	root := filepath.Dir(cpuRoot)
63 61
 
64 62
 	if _, err := os.Stat(root); err != nil {
65 63
 		return "", err
... ...
@@ -231,6 +229,12 @@ func (raw *data) parent(subsystem string) (string, error) {
231 231
 }
232 232
 
233 233
 func (raw *data) path(subsystem string) (string, error) {
234
+	_, err := cgroups.FindCgroupMountpoint(subsystem)
235
+	// If we didn't mount the subsystem, there is no point we make the path.
236
+	if err != nil {
237
+		return "", err
238
+	}
239
+
234 240
 	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
235 241
 	if filepath.IsAbs(raw.cgroup) {
236 242
 		path := filepath.Join(raw.root, subsystem, raw.cgroup)
... ...
@@ -17,8 +17,12 @@ type BlkioGroup struct {
17 17
 
18 18
 func (s *BlkioGroup) Apply(d *data) error {
19 19
 	dir, err := d.join("blkio")
20
-	if err != nil && !cgroups.IsNotFound(err) {
21
-		return err
20
+	if err != nil {
21
+		if cgroups.IsNotFound(err) {
22
+			return nil
23
+		} else {
24
+			return err
25
+		}
22 26
 	}
23 27
 
24 28
 	if err := s.Set(dir, d.c); err != nil {
... ...
@@ -18,7 +18,11 @@ func (s *CpuGroup) Apply(d *data) error {
18 18
 	// on a container basis
19 19
 	dir, err := d.join("cpu")
20 20
 	if err != nil {
21
-		return err
21
+		if cgroups.IsNotFound(err) {
22
+			return nil
23
+		} else {
24
+			return err
25
+		}
22 26
 	}
23 27
 
24 28
 	if err := s.Set(dir, d.c); err != nil {
... ...
@@ -17,7 +17,11 @@ type CpusetGroup struct {
17 17
 func (s *CpusetGroup) Apply(d *data) error {
18 18
 	dir, err := d.path("cpuset")
19 19
 	if err != nil {
20
-		return err
20
+		if cgroups.IsNotFound(err) {
21
+			return nil
22
+		} else {
23
+			return err
24
+		}
21 25
 	}
22 26
 	return s.ApplyDir(dir, d.c, d.pid)
23 27
 }
... ...
@@ -11,7 +11,11 @@ type DevicesGroup struct {
11 11
 func (s *DevicesGroup) Apply(d *data) error {
12 12
 	dir, err := d.join("devices")
13 13
 	if err != nil {
14
-		return err
14
+		if cgroups.IsNotFound(err) {
15
+			return nil
16
+		} else {
17
+			return err
18
+		}
15 19
 	}
16 20
 
17 21
 	if err := s.Set(dir, d.c); err != nil {
... ...
@@ -25,7 +25,7 @@ func TestDevicesSetAllow(t *testing.T) {
25 25
 	defer helper.cleanup()
26 26
 
27 27
 	helper.writeFileContents(map[string]string{
28
-		"device.deny": "a",
28
+		"devices.deny": "a",
29 29
 	})
30 30
 
31 31
 	helper.CgroupData.c.AllowAllDevices = false
... ...
@@ -35,8 +35,6 @@ func TestDevicesSetAllow(t *testing.T) {
35 35
 		t.Fatal(err)
36 36
 	}
37 37
 
38
-	// FIXME: this doesn't make sence, the file devices.allow under real cgroupfs
39
-	// is not allowed to read. Our test path don't have cgroupfs mounted.
40 38
 	value, err := getCgroupParamString(helper.CgroupPath, "devices.allow")
41 39
 	if err != nil {
42 40
 		t.Fatalf("Failed to parse devices.allow - %s", err)
... ...
@@ -13,8 +13,12 @@ type FreezerGroup struct {
13 13
 
14 14
 func (s *FreezerGroup) Apply(d *data) error {
15 15
 	dir, err := d.join("freezer")
16
-	if err != nil && !cgroups.IsNotFound(err) {
17
-		return err
16
+	if err != nil {
17
+		if cgroups.IsNotFound(err) {
18
+			return nil
19
+		} else {
20
+			return err
21
+		}
18 22
 	}
19 23
 
20 24
 	if err := s.Set(dir, d.c); err != nil {
... ...
@@ -16,9 +16,12 @@ type MemoryGroup struct {
16 16
 
17 17
 func (s *MemoryGroup) Apply(d *data) error {
18 18
 	dir, err := d.join("memory")
19
-	// only return an error for memory if it was specified
20
-	if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
21
-		return err
19
+	if err != nil {
20
+		if cgroups.IsNotFound(err) {
21
+			return nil
22
+		} else {
23
+			return err
24
+		}
22 25
 	}
23 26
 	defer func() {
24 27
 		if err != nil {
... ...
@@ -55,6 +55,63 @@ func TestMemorySetMemory(t *testing.T) {
55 55
 	}
56 56
 }
57 57
 
58
+func TestMemorySetMemoryswap(t *testing.T) {
59
+	helper := NewCgroupTestUtil("memory", t)
60
+	defer helper.cleanup()
61
+
62
+	const (
63
+		memoryswapBefore = 314572800 // 300M
64
+		memoryswapAfter  = 524288000 // 500M
65
+	)
66
+
67
+	helper.writeFileContents(map[string]string{
68
+		"memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore),
69
+	})
70
+
71
+	helper.CgroupData.c.MemorySwap = memoryswapAfter
72
+	memory := &MemoryGroup{}
73
+	if err := memory.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
74
+		t.Fatal(err)
75
+	}
76
+
77
+	value, err := getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes")
78
+	if err != nil {
79
+		t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err)
80
+	}
81
+	if value != memoryswapAfter {
82
+		t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.")
83
+	}
84
+}
85
+
86
+func TestMemorySetMemoryswapDefault(t *testing.T) {
87
+	helper := NewCgroupTestUtil("memory", t)
88
+	defer helper.cleanup()
89
+
90
+	const (
91
+		memoryBefore    = 209715200 // 200M
92
+		memoryAfter     = 314572800 // 300M
93
+		memoryswapAfter = 629145600 // 300M*2
94
+	)
95
+
96
+	helper.writeFileContents(map[string]string{
97
+		"memory.limit_in_bytes": strconv.Itoa(memoryBefore),
98
+	})
99
+
100
+	helper.CgroupData.c.Memory = memoryAfter
101
+	memory := &MemoryGroup{}
102
+	if err := memory.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
103
+		t.Fatal(err)
104
+	}
105
+
106
+	value, err := getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes")
107
+	if err != nil {
108
+		t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err)
109
+	}
110
+	if value != memoryswapAfter {
111
+		t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.")
112
+	}
113
+}
114
+
58 115
 func TestMemoryStats(t *testing.T) {
59 116
 	helper := NewCgroupTestUtil("memory", t)
60 117
 	defer helper.cleanup()
... ...
@@ -6,9 +6,9 @@ Creates a mock of the cgroup filesystem for the duration of the test.
6 6
 package fs
7 7
 
8 8
 import (
9
-	"fmt"
10 9
 	"io/ioutil"
11 10
 	"os"
11
+	"path/filepath"
12 12
 	"testing"
13 13
 
14 14
 	"github.com/docker/libcontainer/configs"
... ...
@@ -31,12 +31,12 @@ func NewCgroupTestUtil(subsystem string, t *testing.T) *cgroupTestUtil {
31 31
 	d := &data{
32 32
 		c: &configs.Cgroup{},
33 33
 	}
34
-	tempDir, err := ioutil.TempDir("", fmt.Sprintf("%s_cgroup_test", subsystem))
34
+	tempDir, err := ioutil.TempDir("", "cgroup_test")
35 35
 	if err != nil {
36 36
 		t.Fatal(err)
37 37
 	}
38 38
 	d.root = tempDir
39
-	testCgroupPath, err := d.path(subsystem)
39
+	testCgroupPath := filepath.Join(d.root, subsystem)
40 40
 	if err != nil {
41 41
 		t.Fatal(err)
42 42
 	}
... ...
@@ -34,6 +34,21 @@ func FindCgroupMountpoint(subsystem string) (string, error) {
34 34
 	return "", NewNotFoundError(subsystem)
35 35
 }
36 36
 
37
+func FindCgroupMountpointDir() (string, error) {
38
+	mounts, err := mount.GetMounts()
39
+	if err != nil {
40
+		return "", err
41
+	}
42
+
43
+	for _, mount := range mounts {
44
+		if mount.Fstype == "cgroup" {
45
+			return filepath.Dir(mount.Mountpoint), nil
46
+		}
47
+	}
48
+
49
+	return "", NewNotFoundError("cgroup")
50
+}
51
+
37 52
 type Mount struct {
38 53
 	Mountpoint string
39 54
 	Subsystems []string
... ...
@@ -1,25 +1,12 @@
1
-// +build linux
1
+// +build linux,!gccgo
2 2
 
3 3
 package nsenter
4 4
 
5 5
 /*
6 6
 #cgo CFLAGS: -Wall
7 7
 extern void nsexec();
8
-void __attribute__((constructor)) init() {
8
+void __attribute__((constructor)) init(void) {
9 9
 	nsexec();
10 10
 }
11 11
 */
12 12
 import "C"
13
-
14
-// AlwaysFalse is here to stay false
15
-// (and be exported so the compiler doesn't optimize out its reference)
16
-var AlwaysFalse bool
17
-
18
-func init() {
19
-	if AlwaysFalse {
20
-		// by referencing this C init() in a noop test, it will ensure the compiler
21
-		// links in the C function.
22
-		// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65134
23
-		C.init()
24
-	}
25
-}
26 13
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+// +build linux,gccgo
1
+
2
+package nsenter
3
+
4
+/*
5
+#cgo CFLAGS: -Wall
6
+extern void nsexec();
7
+void __attribute__((constructor)) init(void) {
8
+	nsexec();
9
+}
10
+*/
11
+import "C"
12
+
13
+// AlwaysFalse is here to stay false
14
+// (and be exported so the compiler doesn't optimize out its reference)
15
+var AlwaysFalse bool
16
+
17
+func init() {
18
+	if AlwaysFalse {
19
+		// by referencing this C init() in a noop test, it will ensure the compiler
20
+		// links in the C function.
21
+		// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65134
22
+		C.init()
23
+	}
24
+}
... ...
@@ -104,6 +104,10 @@ func mount(m *configs.Mount, rootfs, mountLabel string) error {
104 104
 		if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
105 105
 			return err
106 106
 		}
107
+		if m.Device == "mqueue" {
108
+			// mqueue should not be labeled, otherwise the mount will fail
109
+			data = ""
110
+		}
107 111
 		return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data)
108 112
 	case "bind":
109 113
 		stat, err := os.Stat(m.Source)
... ...
@@ -37,8 +37,8 @@ var (
37 37
 	spaceRegex            = regexp.MustCompile(`^([^=]+) (.*)$`)
38 38
 	mcsList               = make(map[string]bool)
39 39
 	selinuxfs             = "unknown"
40
-	selinuxEnabled        = false
41
-	selinuxEnabledChecked = false
40
+	selinuxEnabled        = false // Stores whether selinux is currently enabled
41
+	selinuxEnabledChecked = false // Stores whether selinux enablement has been checked or established yet
42 42
 )
43 43
 
44 44
 type SELinuxContext map[string]string
... ...
@@ -48,6 +48,11 @@ func SetDisabled() {
48 48
 	selinuxEnabled, selinuxEnabledChecked = false, true
49 49
 }
50 50
 
51
+// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
52
+// filesystem or an empty string if no mountpoint is found.  Selinuxfs is
53
+// a proc-like pseudo-filesystem that exposes the selinux policy API to
54
+// processes.  The existence of an selinuxfs mount is used to determine
55
+// whether selinux is currently enabled or not.
51 56
 func getSelinuxMountPoint() string {
52 57
 	if selinuxfs != "unknown" {
53 58
 		return selinuxfs
... ...
@@ -74,6 +79,7 @@ func getSelinuxMountPoint() string {
74 74
 	return selinuxfs
75 75
 }
76 76
 
77
+// SelinuxEnabled returns whether selinux is currently enabled.
77 78
 func SelinuxEnabled() bool {
78 79
 	if selinuxEnabledChecked {
79 80
 		return selinuxEnabled
... ...
@@ -145,11 +151,12 @@ func readCon(name string) (string, error) {
145 145
 	return val, err
146 146
 }
147 147
 
148
+// Setfilecon sets the SELinux label for this path or returns an error.
148 149
 func Setfilecon(path string, scon string) error {
149 150
 	return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0)
150 151
 }
151 152
 
152
-// Return the SELinux label for this path
153
+// Getfilecon returns the SELinux label for this path or returns an error.
153 154
 func Getfilecon(path string) (string, error) {
154 155
 	con, err := system.Lgetxattr(path, xattrNameSelinux)
155 156
 	return string(con), err
... ...
@@ -163,11 +170,12 @@ func Getfscreatecon() (string, error) {
163 163
 	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()))
164 164
 }
165 165
 
166
-// Return the SELinux label of the current process thread.
166
+// Getcon returns the SELinux label of the current process thread, or an error.
167 167
 func Getcon() (string, error) {
168 168
 	return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()))
169 169
 }
170 170
 
171
+// Getpidcon returns the SELinux label of the given pid, or an error.
171 172
 func Getpidcon(pid int) (string, error) {
172 173
 	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
173 174
 }