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;
}
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)
--- /dev/null
+#!/bin/bash
+
+# lxc: linux Container library
+
+# Authors:
+# Serge Hallyn <serge.hallyn@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