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@ubuntu.com>
This commit is contained in:
Serge Hallyn 2016-03-15 23:01:42 -07:00
parent e6bff191fb
commit 8aa1044fd8
4 changed files with 372 additions and 6 deletions

View File

@ -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)

1
src/lxc/liblxc.so.1 Symbolic link
View File

@ -0,0 +1 @@
liblxc.so

View File

@ -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 \

View File

@ -0,0 +1,217 @@
#!/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