[lxc-devel] [lxc/master] 2016 03 16/cgroupauto

hallyn on Github lxc-bot at linuxcontainers.org
Wed Mar 16 23:56:27 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 403 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160316/8434672c/attachment.bin>
-------------- next part --------------
From 8aa1044fd83c407e38c66a1ff46a9edfe02d7c78 Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge.hallyn at ubuntu.com>
Date: Tue, 15 Mar 2016 23:01:42 -0700
Subject: [PATCH 1/2] implement lxc.mount.auto = cgroup for cgfsng

Also add testcase for each of the cgroup{,-full}:{rw,ro,mixed} cases.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/cgfsng.c             | 156 ++++++++++++++++++++++++++++++-
 src/lxc/liblxc.so.1          |   1 +
 src/tests/Makefile.am        |   4 +-
 src/tests/lxc-test-automount | 217 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 372 insertions(+), 6 deletions(-)
 create mode 120000 src/lxc/liblxc.so.1
 create mode 100644 src/tests/lxc-test-automount

diff --git a/src/lxc/cgfsng.c b/src/lxc/cgfsng.c
index a6767c5..4a49226 100644
--- a/src/lxc/cgfsng.c
+++ b/src/lxc/cgfsng.c
@@ -1022,9 +1022,6 @@ static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
 
 struct cgroup_ops *cgfsng_ops_init(void)
 {
-	/* TODO - when cgroup_mount is implemented, drop this check */
-	if (!file_exists("/proc/self/ns/cgroup"))
-		return NULL;
 	return &cgfsng_ops;
 }
 
@@ -1223,12 +1220,161 @@ static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
 	return true;
 }
 
+/*
+ * We've safe-mounted a tmpfs as parent, so we don't need to protect against
+ * symlinks any more - just use mount
+ */
+
+/* mount cgroup-full if requested */
+static int mount_cgroup_full(int type, struct hierarchy *h, char *dest,
+				   char *container_cgroup)
+{
+	if (type < LXC_AUTO_CGROUP_FULL_RO || type > LXC_AUTO_CGROUP_FULL_MIXED)
+		return 0;
+	if (mount(h->mountpoint, dest, "cgroup", MS_BIND, NULL) < 0) {
+		SYSERROR("Error bind-mounting %s cgroup onto %s", h->mountpoint,
+			 dest);
+		return -1;
+	}
+	if (type != LXC_AUTO_CGROUP_FULL_RW) {
+		if (mount(NULL, dest, "cgroup", MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0) {
+			SYSERROR("Error remounting %s readonly", dest);
+			return -1;
+		}
+	}
+
+	INFO("Bind mounted %s onto %s", h->mountpoint, dest);
+	if (type != LXC_AUTO_CGROUP_FULL_MIXED)
+		return 0;
+
+	/* mount just the container path rw */
+	char *source = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
+	char *rwpath = must_make_path(dest, container_cgroup, NULL);
+	if (mount(source, rwpath, "cgroup", MS_BIND, NULL) < 0)
+		WARN("Failed to mount %s read-write: %m", rwpath);
+	INFO("Made %s read-write", rwpath);
+	free(rwpath);
+	free(source);
+	return 0;
+}
+
+/* cgroup-full:* is done, no need to create subdirs */
+static bool cg_mount_needs_subdirs(int type)
+{
+	if (type >= LXC_AUTO_CGROUP_FULL_RO)
+		return false;
+	return true;
+}
+
+/*
+ * After $rootfs/sys/fs/container/controller/the/cg/path has been
+ * created, remount controller ro if needed and bindmount the
+ * cgroupfs onto controll/the/cg/path
+ */
+static int
+do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
+				char *controllerpath, char *cgpath,
+				const char *container_cgroup)
+{
+	if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) {
+		if (mount(controllerpath, controllerpath, "cgroup", MS_BIND, NULL) < 0) {
+			SYSERROR("Error bind-mounting %s", controllerpath);
+			return -1;
+		}
+		if (mount(controllerpath, controllerpath, "cgroup",
+			   MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) < 0) {
+			SYSERROR("Error remounting %s read-only", controllerpath);
+			return -1;
+		}
+		INFO("Remounted %s read-only", controllerpath);
+	}
+	char *sourcepath = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
+	int flags = MS_BIND;
+	if (type == LXC_AUTO_CGROUP_RO)
+		flags |= MS_RDONLY;
+	INFO("Mounting %s onto %s", sourcepath, cgpath);
+	if (mount(sourcepath, cgpath, "cgroup", flags, NULL) < 0) {
+		free(sourcepath);
+		SYSERROR("Error mounting cgroup %s onto %s", h->controllers[0],
+				cgpath);
+		return -1;
+	}
+	free(sourcepath);
+	INFO("Completed second stage cgroup automounts for %s", cgpath);
+	return 0;
+}
+
 static bool cgfsng_mount(void *hdata, const char *root, int type)
 {
+	struct cgfsng_handler_data *d = hdata;
+	char *tmpfspath = NULL;
+	bool retval = false;
+
+	if ((type & LXC_AUTO_CGROUP_MASK) == 0)
+		return true;
+
 	if (cgns_supported())
 		return true;
-	// TODO - implement this.  Not needed for cgroup namespaces
-	return false;
+
+	tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
+
+	if (type == LXC_AUTO_CGROUP_NOSPEC)
+		type = LXC_AUTO_CGROUP_MIXED;
+	else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
+		type = LXC_AUTO_CGROUP_FULL_MIXED;
+
+	/* Mount tmpfs */
+	if (safe_mount("cgroup_root", tmpfspath, "tmpfs",
+			MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
+			"size=10240k,mode=755",
+			root) < 0)
+		goto  bad;
+
+	for (int i = 0; d->hierarchies[i]; i++) {
+		char *controllerpath, *path2;
+		struct hierarchy *h = d->hierarchies[i];
+		char *controller = strrchr(h->mountpoint, '/');
+		int r;
+
+		if (!controller)
+			continue;
+		controller++;
+		controllerpath = must_make_path(tmpfspath, controller, NULL);
+		if (dir_exists(controllerpath)) {
+			free(controllerpath);
+			continue;
+		}
+		if (mkdir(controllerpath, 0755) < 0) {
+			SYSERROR("Error creating cgroup path: %s", controllerpath);
+			free(controllerpath);
+			goto bad;
+		}
+		if (mount_cgroup_full(type, h, controllerpath, d->container_cgroup) < 0) {
+			free(controllerpath);
+			goto bad;
+		}
+		if (!cg_mount_needs_subdirs(type)) {
+			free(controllerpath);
+			continue;
+		}
+		path2 = must_make_path(controllerpath, d->container_cgroup, NULL);
+		if (mkdir_p(path2, 0755) < 0) {
+			free(controllerpath);
+			goto bad;
+		}
+		
+		r = do_secondstage_mounts_if_needed(type, h, controllerpath, path2,
+						    d->container_cgroup);
+		free(controllerpath);
+		free(path2);
+		if (r < 0)
+			goto bad;
+	}
+	retval = true;
+
+bad:
+	free(tmpfspath);
+	return retval;
 }
 
 static int recursive_count_nrtasks(char *dirname)
diff --git a/src/lxc/liblxc.so.1 b/src/lxc/liblxc.so.1
new file mode 120000
index 0000000..824cc6c
--- /dev/null
+++ b/src/lxc/liblxc.so.1
@@ -0,0 +1 @@
+liblxc.so
\ No newline at end of file
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 5151dca..68141f9 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -48,7 +48,8 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \
 	lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove \
 	lxc-test-apparmor
 
-bin_SCRIPTS = lxc-test-autostart lxc-test-cloneconfig lxc-test-createconfig
+bin_SCRIPTS = lxc-test-automount lxc-test-autostart lxc-test-cloneconfig \
+	lxc-test-createconfig
 
 if DISTRO_UBUNTU
 bin_SCRIPTS += \
@@ -79,6 +80,7 @@ EXTRA_DIST = \
 	locktests.c \
 	lxcpath.c \
 	lxc-test-lxc-attach \
+	lxc-test-automount \
 	lxc-test-autostart \
 	lxc-test-apparmor-mount \
 	lxc-test-checkpoint-restore \
diff --git a/src/tests/lxc-test-automount b/src/tests/lxc-test-automount
new file mode 100644
index 0000000..6a06d7a
--- /dev/null
+++ b/src/tests/lxc-test-automount
@@ -0,0 +1,217 @@
+#!/bin/bash
+
+# lxc: linux Container library
+
+# Authors:
+# Serge Hallyn <serge.hallyn at ubuntu.com>
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# At the moment this only tests cgroup automount.  Testing proc and
+# sys automounts would be worthwhile.
+
+[ -f /proc/self/ns/cgroup ] && exit 0
+
+set -ex
+
+cleanup() {
+	set +e
+	rmdir /sys/fs/cgroup/freezer/xx
+	lxc-destroy -n lxc-test-automount -f
+	if [ $PHASE != "done" ]; then
+		echo "automount test failed at $PHASE"
+		exit 1
+	fi
+	echo "automount test passed"
+	exit 0
+}
+
+PHASE=setup
+trap cleanup EXIT
+
+rmdir /sys/fs/cgroup/freezer/xx || true
+lxc-destroy -n lxc-test-automount -f || true
+lxc-create -t busybox -n lxc-test-automount
+
+PHASE=no-cgroup
+echo "Starting phase $PHASE"
+config=/var/lib/lxc/lxc-test-automount/config
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = proc:mixed sys:mixed" >> $config
+
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 0 ]
+
+# Tests are as follows:
+# 1. check that freezer controller is mounted
+# 2. check that it is cgroupfs for cgroup-full (/cgroup.procs exists) or
+#    tmpfs for cgroup
+# 3. check that root cgroup dir is readonly or not (try mkdir)
+# 4. check that the container's cgroup dir is readonly or not
+# 5. check that the container's cgroup dir is cgroupfs (/cgroup.procs exists)
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup:mixed
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup:ro
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup:ro proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup:rw
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup:rw proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 1 ]
+rmdir /proc/$pid/root/sys/fs/cgroup/freezer/xx
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+# cgroup-full
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup-full:mixed
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup-full:mixed  proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+rmdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup-full:ro
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup-full:ro proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 0 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xy || ro=1
+[ $ro -ne 0 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+
+lxc-stop -n lxc-test-automount -k
+PHASE=cgroup-full:rw
+echo "Starting phase $PHASE"
+sed -i '/lxc.mount.auto/d' $config
+echo "lxc.mount.auto = cgroup-full:rw proc:mixed sys:mixed" >> $config
+lxc-start -n lxc-test-automount
+pid=`lxc-info -n lxc-test-automount -p -H`
+cg=`awk -F: '/freezer/ { print $3 }' /proc/$pid/cgroup`
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer || notfound=1
+[ $notfound -ne 1 ]
+notfound=0
+stat /proc/$pid/root/sys/fs/cgroup/freezer/cgroup.procs || notfound=1
+[ $notfound -ne 1 ]
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/xx || ro=1
+[ $ro -ne 1 ]
+rmdir /proc/$pid/root/sys/fs/cgroup/freezer/xx
+ro=0
+mkdir /proc/$pid/root/sys/fs/cgroup/freezer/$cg/xx || ro=1
+[ $ro -ne 1 ]
+notfound=0
+/proc/$pid/root/sys/fs/cgroup/freezer/$cg/cgroup.procs || notfound=1
+[ $notfound -eq 1 ]
+
+PHASE=done

From 9ec45e7faa3648a36cb01aed9e230bd49b450fe0 Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge.hallyn at ubuntu.com>
Date: Tue, 15 Mar 2016 23:02:10 -0700
Subject: [PATCH 2/2] cgroups: try to load cgmanager first

If cgmanager is running, use it.  This allows the admin to simply
stop cgmanager if they don't want to use it.  The other way there
is no way to choose to use cgmanager.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/cgroup.c             | 6 +++---
 src/tests/lxc-test-automount | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index 684a3c3..1a92ef4 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -46,12 +46,12 @@ void cgroup_ops_init(void)
 	}
 
 	DEBUG("cgroup_init");
-	ops = cgfsng_ops_init();
 	#if HAVE_CGMANAGER
-	if (!ops)
-		ops = cgm_ops_init();
+	ops = cgm_ops_init();
 	#endif
 	if (!ops)
+		ops = cgfsng_ops_init();
+	if (!ops)
 		ops = cgfs_ops_init();
 	if (ops)
 		INFO("Initialized cgroup driver %s", ops->name);
diff --git a/src/tests/lxc-test-automount b/src/tests/lxc-test-automount
index 6a06d7a..4505375 100644
--- a/src/tests/lxc-test-automount
+++ b/src/tests/lxc-test-automount
@@ -24,6 +24,9 @@
 
 [ -f /proc/self/ns/cgroup ] && exit 0
 
+# cgmanager doesn't do the same cgroup filesystem mounting
+cgm ping && exit 0
+
 set -ex
 
 cleanup() {


More information about the lxc-devel mailing list