[lxc-devel] [PATCH 1/1] Initial support for cgmanager

Serge Hallyn serge.hallyn at ubuntu.com
Tue Jan 14 22:41:36 UTC 2014


This patch splits out most of the cgroupfs-specific code, so that
cgroup-manager versions can be plugged in.  The case I did
not handle is cgroup_enter at lxc_attach.  I'm hoping that case can
be greatly simplified, but will worry about it after fleshing out the
cgroup manager handlers.

This also simplify the freezer functions.

This seems to not regress my common tests when running without
cgmanager, but I'd like to do a bit more testing before pushing.
However I was hoping to get some more eyes on this so am sending it
out now.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 configure.ac        |  18 +++
 src/lxc/Makefile.am |  18 +++
 src/lxc/attach.c    |   6 +-
 src/lxc/cgmanager.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/cgroup.c    | 350 ++++++++++++++++++++++++++++++++-----------------
 src/lxc/cgroup.h    |  61 +++++++--
 src/lxc/commands.c  |  13 +-
 src/lxc/conf.c      |  10 +-
 src/lxc/conf.h      |   5 +-
 src/lxc/freezer.c   |  14 --
 src/lxc/lxc.h       |   8 --
 src/lxc/start.c     |  47 ++-----
 src/lxc/start.h     |   2 +-
 13 files changed, 718 insertions(+), 201 deletions(-)
 create mode 100644 src/lxc/cgmanager.c

diff --git a/configure.ac b/configure.ac
index 8514267..e513bbe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -240,6 +240,23 @@ AM_COND_IF([ENABLE_SECCOMP],
 		])
 	])
 
+# cgmanager
+AC_ARG_ENABLE([cgmanager],
+	[AC_HELP_STRING([--enable-cgmanager], [enable cgmanager support [default=auto]])],
+	[], [enable_cgmanager=auto])
+
+if test "x$enable_cgmanager" = "xauto" ; then
+	AC_CHECK_LIB([cgmanager],[cgmanager_create],[enable_cgmanager=yes],[enable_cgmanager=no])
+fi
+AM_CONDITIONAL([ENABLE_CGMANAGER], [test "x$enable_cgmanager" = "xyes"])
+
+AM_COND_IF([ENABLE_CGMANAGER],
+	[PKG_CHECK_MODULES([CGMANAGER], [libcgmanager])
+	PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
+	PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
+	PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
+	])
+
 # Linux capabilities
 AC_ARG_ENABLE([capabilities],
 	[AC_HELP_STRING([--enable-capabilities], [enable kernel capabilities support [default=auto]])],
@@ -684,6 +701,7 @@ Security features:
  - Linux capabilities: $enable_capabilities
  - seccomp: $enable_seccomp
  - SELinux: $enable_selinux
+ - cgmanager: $enable_cgmanager
 
 Bindings:
  - lua: $enable_lua
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 1e0232b..34d69a6 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -93,6 +93,10 @@ liblxc_so_SOURCES = \
 	\
 	$(LSM_SOURCES)
 
+if ENABLE_CGMANAGER
+liblxc_so_SOURCES += cgmanager.c
+endif
+
 if IS_BIONIC
 liblxc_so_SOURCES += \
 	../include/ifaddrs.c ../include/ifaddrs.h \
@@ -122,6 +126,10 @@ if ENABLE_APPARMOR
 AM_CFLAGS += -DHAVE_APPARMOR
 endif
 
+if ENABLE_CGMANAGER
+AM_CFLAGS += -DHAVE_CGMANAGER
+endif
+
 if ENABLE_SELINUX
 AM_CFLAGS += -DHAVE_SELINUX
 endif
@@ -144,6 +152,11 @@ liblxc_so_LDFLAGS = \
 
 liblxc_so_LDADD = $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS)
 
+#if ENABLE_CGMANAGER
+liblxc_so_LDADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
+liblxc_so_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
+#endif
+
 bin_SCRIPTS = \
 	lxc-ps \
 	lxc-netstat \
@@ -245,6 +258,11 @@ LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@
 lxc_attach_SOURCES = lxc_attach.c
 lxc_autostart_SOURCES = lxc_autostart.c
 lxc_cgroup_SOURCES = lxc_cgroup.c
+#if ENABLE_CGMANAGER
+lxc_cgroup_SOURCES += cgmanager.c
+lxc_cgroup_LDADD = $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS) $(LDADD)
+lxc_cgroup_CFLAGS = $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
+#endif
 lxc_checkpoint_SOURCES = lxc_checkpoint.c
 lxc_config_SOURCES = lxc_config.c
 lxc_console_SOURCES = lxc_console.c
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 422f24c..de32549 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -748,7 +748,11 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
 				goto cleanup_error;
 			}
 
-			ret = lxc_cgroup_enter(container_info, attached_pid, false);
+			/*
+			 * TODO - switch over to using a cgroup_operation.  We can't use
+			 * cgroup_enter() as that takes a handler.
+			 */
+			ret = lxc_cgroupfs_enter(container_info, attached_pid, false);
 			lxc_cgroup_process_info_free(container_info);
 			if (ret < 0) {
 				ERROR("could not move attached process %ld to cgroup of container", (long)attached_pid);
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
new file mode 100644
index 0000000..92745dc
--- /dev/null
+++ b/src/lxc/cgmanager.c
@@ -0,0 +1,367 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * 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
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include "error.h"
+#include "config.h"
+#include "commands.h"
+#include "list.h"
+#include "conf.h"
+#include "utils.h"
+#include "bdev.h"
+#include "log.h"
+#include "cgroup.h"
+#include "start.h"
+#include "state.h"
+
+#ifdef HAVE_CGMANAGER
+lxc_log_define(lxc_cgmanager, lxc);
+
+#include <nih-dbus/dbus_connection.h>
+#include <cgmanager-client/cgmanager-client.h>
+NihDBusProxy *cgroup_manager = NULL;
+
+extern struct cgroup_ops *active_cg_ops;
+bool cgmanager_initialized = false;
+bool use_cgmanager = true;
+static struct cgroup_ops cgmanager_ops;
+
+bool lxc_init_cgmanager(void);
+static void cgmanager_disconnected(DBusConnection *connection)
+{
+	WARN("Cgroup manager connection was terminated");
+	cgroup_manager = NULL;
+	cgmanager_initialized = false;
+	if (lxc_init_cgmanager()) {
+		cgmanager_initialized = true;
+		INFO("New cgroup manager connection was opened");
+	}
+}
+
+#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
+bool lxc_init_cgmanager(void)
+{
+	DBusError dbus_error;
+	DBusConnection *connection;
+	dbus_error_init(&dbus_error);
+
+	connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, cgmanager_disconnected);
+	if (!connection) {
+		ERROR("Error opening cgmanager connection at %s", CGMANAGER_DBUS_SOCK);
+		return false;
+	}
+	dbus_connection_set_exit_on_disconnect(connection, FALSE);
+	dbus_error_free(&dbus_error);
+	cgroup_manager = nih_dbus_proxy_new(NULL, connection,
+				NULL /* p2p */,
+				"/org/linuxcontainers/cgmanager", NULL, NULL);
+	dbus_connection_unref(connection);
+	if (!cgroup_manager) {
+		return false;
+	}
+	active_cg_ops = &cgmanager_ops;
+	return true;
+}
+
+/*
+ * Use the cgmanager to move a task into a cgroup for a particular
+ * hierarchy.
+ * All the subsystems in this hierarchy are co-mounted, so we only
+ * need to transition the task into one of the cgroups
+ */
+static bool lxc_cgmanager_enter(pid_t pid, char *controller, char *cgroup_path)
+{
+	return cgmanager_move_pid_sync(NULL, cgroup_manager, controller,
+				       cgroup_path, pid) == 0;
+}
+
+static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
+{
+	if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
+				       cgroup_path, existed) != 0) {
+		ERROR("Failed to create %s:%s", controller, cgroup_path);
+		return false;
+	}
+
+	// TODO - try to chown the cgroup to the container root
+	return true;
+}
+
+
+struct cgm_data {
+	int nr_subsystems;
+	char **subsystems;
+	char *cgroup_path;
+};
+
+void cgmanager_remove_cgroup(const char *subsystem, const char *path)
+{
+	// TODO implement
+	WARN("%s: not yet implemented", __func__);
+}
+
+static void cgm_destroy(struct lxc_handler *handler)
+{
+	struct cgm_data *d = handler->cgroup_info->data;
+	int i;
+
+	if (!d)
+		return;
+	for (i=0; i<d->nr_subsystems; i++) {
+		if (d->cgroup_path)
+			cgmanager_remove_cgroup(d->subsystems[i], d->cgroup_path);
+		free(d->subsystems[i]);
+	}
+	free(d->subsystems);
+	free(d->cgroup_path);
+	free(d);
+	handler->cgroup_info->data = NULL;
+}
+
+/*
+ * remove all the cgroups created
+ */
+static inline void cleanup_cgroups(struct cgm_data *d, char *path)
+{
+	int i;
+	for (i = 0; i < d->nr_subsystems; i++) {
+		cgmanager_remove_cgroup(d->subsystems[i], path);
+	}
+}
+
+static inline bool cgm_create(struct lxc_handler *handler)
+{
+	int i, index=0, baselen, ret;
+	int32_t existed;
+	char result[MAXPATHLEN], *tmp;
+	struct cgm_data *d = handler->cgroup_info->data;
+
+// XXX we should send a hint to the cgmanager that when these
+// cgroups become empty they should be deleted.  Requires a cgmanager
+// extension
+
+	memset(result, 0, MAXPATHLEN);
+	tmp = lxc_string_replace("%n", handler->name, handler->cgroup_info->cgroup_pattern);
+	if (!tmp)
+		return false;
+	if (strlen(tmp) > MAXPATHLEN)
+		return false;
+	strcpy(result, tmp);
+	baselen = strlen(result);
+	free(tmp);
+	tmp = result;
+	while (*tmp == '/')
+		tmp++;
+again:
+	if (index == 100) { // turn this into a warn later
+		ERROR("cgroup error?  100 cgroups with this name already running");
+		return false;
+	}
+	if (index) {
+		ret = snprintf(result+baselen, MAXPATHLEN-baselen, "-%d", index);
+		if (ret < 0 || ret >= MAXPATHLEN-baselen)
+			return false;
+	}
+	existed = 0;
+	for (i = 0; i < d->nr_subsystems; i++) {
+		if (!lxc_cgmanager_create(d->subsystems[i], tmp, &existed)) {
+			ERROR("Error creating cgroup %s:%s", d->subsystems[i], result);
+			cleanup_cgroups(d, tmp);
+			return false;
+		}
+		if (existed)
+			goto next;
+	}
+	// success
+	d->cgroup_path = strdup(tmp);
+	if (!d->cgroup_path) {
+		cleanup_cgroups(d, tmp);
+		return false;
+	}
+	return true;
+next:
+	cleanup_cgroups(d, tmp);
+	index++;
+	goto again;
+}
+
+static inline bool cgm_enter(struct lxc_handler *handler)
+{
+	struct cgm_data *d = handler->cgroup_info->data;
+	int i;
+
+	for (i = 0; i < d->nr_subsystems; i++) {
+		if (!lxc_cgmanager_enter(handler->pid, d->subsystems[i], d->cgroup_path))
+			return false;
+	}
+	return true;
+}
+
+static char *cgm_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+{
+	struct cgm_data *d = handler->cgroup_info->data;
+	return d->cgroup_path;
+}
+
+int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	char *result, *controller, *key, *cgroup;
+
+	controller = alloca(strlen(filename)+1);
+	key = strchr(controller, '.');
+	if (!key)
+		return false;
+	*key = '\0';
+	key++;
+
+	/* use the command interface to look for the cgroup */
+	cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
+	if (!cgroup) {
+		ERROR("Failed to get cgroup for controller %s for %s:%s",
+			controller, lxcpath, name);
+		return false;
+	}
+	if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup, key, &result) != 0) {
+		ERROR("Error getting value for %s from cgmanager for cgroup %s (%s:%s)",
+			filename, cgroup, lxcpath, name);
+		free(cgroup);
+		return false;
+	}
+	free(cgroup);
+	strncpy(value, result, len);
+	if (strlen(result) >= len)
+		value[len-1] = '\0';
+	free(result);
+	return true;
+}
+
+int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	char *controller, *key, *cgroup;
+
+	controller = alloca(strlen(filename)+1);
+	key = strchr(controller, '.');
+	if (!key)
+		return false;
+	*key = '\0';
+	key++;
+
+	/* use the command interface to look for the cgroup */
+	cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
+	if (!cgroup) {
+		ERROR("Failed to get cgroup for controller %s for %s:%s",
+			controller, lxcpath, name);
+		return false;
+	}
+	if (cgmanager_set_value_sync(NULL, cgroup_manager, controller, cgroup, key, value) != 0) {
+		ERROR("Error setting value for %s from cgmanager for cgroup %s (%s:%s)",
+			filename, cgroup, lxcpath, name);
+		free(cgroup);
+		return false;
+	}
+	free(cgroup);
+	return true;
+}
+
+/*
+ * TODO really this should be done once for global data, not once
+ * per container
+ */
+static inline bool cgm_init(struct lxc_handler *handler)
+{
+	struct cgm_data *d = malloc(sizeof(*d));
+	char *line = NULL, *tab1;
+	size_t sz = 0, i;
+	FILE *f;
+
+	if (!d)
+		return false;
+	d->nr_subsystems = 0;
+	d->subsystems = NULL;
+	f = fopen_cloexec("/proc/cgroups", "r");
+	if (!f) {
+		free(d);
+		return false;
+	}
+	while (getline(&line, &sz, f) != -1) {
+		char **tmp;
+		if (line[0] == '#')
+			continue;
+		if (!line[0])
+			continue;
+		tab1 = strchr(line, '\t');
+		if (!tab1)
+			continue;
+		*tab1 = '\0';
+		tmp = realloc(d->subsystems, (d->nr_subsystems+1)*sizeof(char *));
+		if (!tmp) {
+			goto out_free;
+		}
+		d->subsystems = tmp;
+		d->subsystems[d->nr_subsystems] = strdup(line);
+		if (!d->subsystems[d->nr_subsystems])
+			goto out_free;
+		d->nr_subsystems++;
+	}
+	fclose(f);
+
+	d->cgroup_path = NULL;
+	handler->cgroup_info->data = d;
+	return true;
+
+out_free:
+	for (i=0; i<d->nr_subsystems; i++)
+		free(d->subsystems[i]);
+	free(d->subsystems);
+	free(d);
+	return false;
+}
+
+static struct cgroup_ops cgmanager_ops = {
+	.destroy = cgm_destroy,
+	.init = cgm_init,
+	.create = cgm_create,
+	.enter = cgm_enter,
+	.create_legacy = NULL,
+	.get_cgroup = cgm_get_cgroup,
+	.get = cgm_get,
+	.set = cgm_set,
+	.name = "cgmanager"
+};
+#endif
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index 6d837f9..efc3e23 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -76,6 +76,21 @@ static int cgroup_recursive_task_count(const char *cgroup_path);
 static int count_lines(const char *fn);
 static int handle_cgroup_settings(struct cgroup_mount_point *mp, char *cgroup_path);
 
+static struct cgroup_ops cgfs_ops;
+struct cgroup_ops *active_cg_ops = &cgfs_ops;
+static void init_cg_ops(void);
+
+#ifdef HAVE_CGMANAGER
+/* this needs to be mutexed for api use */
+extern bool cgmanager_initialized;
+extern bool use_cgmanager;
+extern bool lxc_init_cgmanager(void);
+#else
+static bool cgmanager_initialized = false;
+static bool use_cgmanager = false;
+static bool lxc_init_cgmanager(void) { return false; }
+#endif
+
 static int cgroup_rmdir(char *dirname)
 {
 	struct dirent dirent, *direntp;
@@ -170,7 +185,7 @@ struct cgroup_meta_data *lxc_cgroup_load_meta()
 }
 
 /* Step 1: determine all kernel subsystems */
-static bool find_cgroup_subsystems(char ***kernel_subsystems)
+bool find_cgroup_subsystems(char ***kernel_subsystems)
 {
 	FILE *proc_cgroups;
 	bool bret = false;
@@ -710,7 +725,7 @@ static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, p
 }
 
 /* create a new cgroup */
-extern struct cgroup_process_info *lxc_cgroup_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
+struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
 {
 	char **cgroup_path_components = NULL;
 	char **p = NULL;
@@ -1042,7 +1057,7 @@ out_error:
 }
 
 /* move a processs to the cgroups specified by the membership */
-int lxc_cgroup_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
+int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
 {
 	char pid_buf[32];
 	char *cgroup_tasks_fn;
@@ -1126,9 +1141,11 @@ void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
 	lxc_cgroup_process_info_free_and_remove(next);
 }
 
-char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct lxc_handler *handler)
+static char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct lxc_handler *handler)
 {
-	struct cgroup_process_info *info = find_info_for_subsystem(handler->cgroup, subsystem);
+	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgroup_process_info *info = d->info;
+	info = find_info_for_subsystem(info, subsystem);
 	if (!info)
 		return NULL;
 	return info->cgroup_path;
@@ -1141,8 +1158,11 @@ char *lxc_cgroup_get_hierarchy_path(const char *subsystem, const char *name, con
 
 char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lxc_handler *handler)
 {
+	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgroup_process_info *info = d->info;
 	struct cgroup_mount_point *mp = NULL;
-	struct cgroup_process_info *info = find_info_for_subsystem(handler->cgroup, subsystem);
+
+	info = find_info_for_subsystem(info, subsystem);
 	if (!info)
 		return NULL;
 	if (info->designated_mount_point) {
@@ -1223,7 +1243,7 @@ int lxc_cgroup_get_handler(const char *filename, char *value, size_t len, struct
 	return ret;
 }
 
-int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
 {
 	char *subsystem = NULL, *p, *path;
 	int ret = -1;
@@ -1241,7 +1261,7 @@ int lxc_cgroup_set(const char *filename, const char *value, const char *name, co
 	return ret;
 }
 
-int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
 {
 	char *subsystem = NULL, *p, *path;
 	int ret = -1;
@@ -1299,17 +1319,7 @@ char *lxc_cgroup_path_get(const char *filename, const char *name,
 	return path;
 }
 
-int lxc_setup_cgroup_without_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings)
-{
-	return do_setup_cgroup(h, cgroup_settings, false);
-}
-
-int lxc_setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings)
-{
-	return do_setup_cgroup(h, cgroup_settings, true);
-}
-
-int lxc_setup_mount_cgroup(const char *root, struct cgroup_process_info *base_info, int type)
+int lxc_setup_mount_cgroup(const char *root, struct lxc_cgroup_info *cgroup_info, int type)
 {
 	size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup");
 	char *path = NULL;
@@ -1317,9 +1327,20 @@ int lxc_setup_mount_cgroup(const char *root, struct cgroup_process_info *base_in
 	char *dirname = NULL;
 	char *abs_path = NULL;
 	char *abs_path2 = NULL;
-	struct cgroup_process_info *info;
+	struct cgfs_data *cgfs_d;
+	struct cgroup_process_info *info, *base_info;
 	int r, saved_errno = 0;
 
+	init_cg_ops();
+
+	if (strcmp(active_cg_ops->name, "cgmanager") == 0) {
+		// todo - offer to bind-mount /sys/fs/cgroup/cgmanager/
+		return 0;
+	}
+
+	cgfs_d = cgroup_info->data;
+	base_info = cgfs_d->info;
+
 	if (type < LXC_AUTO_CGROUP_RO || type > LXC_AUTO_CGROUP_FULL_MIXED) {
 		ERROR("could not mount cgroups into container: invalid type specified internally");
 		errno = EINVAL;
@@ -1488,7 +1509,8 @@ out_error:
 
 int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler)
 {
-	struct cgroup_process_info *info = handler->cgroup;
+	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgroup_process_info *info = d->info;
 	struct cgroup_mount_point *mp = NULL;
 	char *abs_path = NULL;
 	int ret;
@@ -2020,133 +2042,227 @@ int handle_cgroup_settings(struct cgroup_mount_point *mp, char *cgroup_path)
 
 extern void lxc_monitor_send_state(const char *name, lxc_state_t state,
 			    const char *lxcpath);
-int do_unfreeze(const char *nsgroup, int freeze, const char *name, const char *lxcpath)
+int do_unfreeze(int freeze, const char *name, const char *lxcpath)
 {
-	char freezer[MAXPATHLEN], *f;
-	char tmpf[32];
-	int fd, ret;
+	char v[100];
+	const char *state = freeze ? "FROZEN" : "THAWED";
 
-	ret = snprintf(freezer, MAXPATHLEN, "%s/freezer.state", nsgroup);
-	if (ret >= MAXPATHLEN) {
-		ERROR("freezer.state name too long");
+	if (lxc_cgroup_set("freezer.state", state, name, lxcpath) < 0) {
+		ERROR("Failed to freeze %s:%s", lxcpath, name);
 		return -1;
 	}
-
-	fd = open(freezer, O_RDWR);
-	if (fd < 0) {
-		SYSERROR("failed to open freezer at '%s'", nsgroup);
-		return -1;
+	while (1) {
+		if (lxc_cgroup_get("freezer.state", v, 100, name, lxcpath) < 0) {
+			ERROR("Failed to get new freezer state for %s:%s", lxcpath, name);
+			return -1;
+		}
+		if (v[strlen(v)-1] == '\n')
+			v[strlen(v)-1] = '\0';
+		if (strncmp(v, state, strlen(state)) == 0) {
+			if (name)
+				lxc_monitor_send_state(name, freeze ? FROZEN : THAWED, lxcpath);
+			return 0;
+		}
+		sleep(1);
 	}
+}
 
-	if (freeze) {
-		f = "FROZEN";
-		ret = write(fd, f, strlen(f) + 1);
-	} else {
-		f = "THAWED";
-		ret = write(fd, f, strlen(f) + 1);
+int freeze_unfreeze(const char *name, int freeze, const char *lxcpath)
+{
+	return do_unfreeze(freeze, name, lxcpath);
+}
 
-		/* compatibility code with old freezer interface */
-		if (ret < 0) {
-			f = "RUNNING";
-			ret = write(fd, f, strlen(f) + 1) < 0;
-		}
+lxc_state_t freezer_state(const char *name, const char *lxcpath)
+{
+	char v[100];
+	if (lxc_cgroup_get("freezer.state", v, 100, name, lxcpath) < 0) {
+		ERROR("Failed to get freezer state for %s:%s", lxcpath, name);
+		return -1;
 	}
 
-	if (ret < 0) {
-		SYSERROR("failed to write '%s' to '%s'", f, freezer);
-		goto out;
-	}
+	if (v[strlen(v)-1] == '\n')
+		v[strlen(v)-1] = '\0';
+	return lxc_str2state(v);
+}
 
-	while (1) {
-		ret = lseek(fd, 0L, SEEK_SET);
-		if (ret < 0) {
-			SYSERROR("failed to lseek on file '%s'", freezer);
-			goto out;
-		}
+static void cgfs_destroy(struct lxc_handler *handler)
+{
+	struct cgfs_data *d = handler->cgroup_info->data;
+	if (!d)
+		return;
+	if (d->info)
+		lxc_cgroup_process_info_free_and_remove(d->info);
+	if (d->meta)
+		lxc_cgroup_put_meta(d->meta);
+	free(d);
+	handler->cgroup_info->data = NULL;
+}
 
-		ret = read(fd, tmpf, sizeof(tmpf));
-		if (ret < 0) {
-			SYSERROR("failed to read to '%s'", freezer);
-			goto out;
-		}
+static inline bool cgfs_init(struct lxc_handler *handler)
+{
+	struct cgfs_data *d = malloc(sizeof(*d));
+	if (!d)
+		return false;
+	d->info = NULL;
+	d->meta = lxc_cgroup_load_meta();
 
-		ret = strncmp(f, tmpf, strlen(f));
-		if (!ret)
-		{
-			if (name)
-				lxc_monitor_send_state(name, freeze ? FROZEN : THAWED, lxcpath);
-			break;		/* Success */
-		}
+	if (!d->meta) {
+		ERROR("cgroupfs failed to detect cgroup metadata");
+		return false;
+	}
+	handler->cgroup_info->data = d;
+	return true;
+}
 
-		sleep(1);
+static inline bool cgfs_create(struct lxc_handler *handler)
+{
+	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgroup_process_info *i;
+	struct cgroup_meta_data *md = d->meta;
+	i = lxc_cgroupfs_create(handler->name, handler->cgroup_info->cgroup_pattern, md, NULL);
+	if (!i)
+		return false;
+	d->info = i;
+	return true;
+}
 
-		ret = lseek(fd, 0L, SEEK_SET);
-		if (ret < 0) {
-			SYSERROR("failed to lseek on file '%s'", freezer);
-			goto out;
-		}
+static inline bool cgfs_enter(struct lxc_handler *handler)
+{
+	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgroup_process_info *i = d->info;
+	int ret;
+	
+	ret = lxc_cgroupfs_enter(i, handler->pid, false);
 
-		ret = write(fd, f, strlen(f) + 1);
-		if (ret < 0) {
-			SYSERROR("failed to write '%s' to '%s'", f, freezer);
-			goto out;
-		}
+	return ret == 0;
+}
+
+static inline bool cgfs_create_legacy(struct lxc_handler *handler)
+{
+	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgroup_process_info *i = d->info;
+	if (lxc_cgroup_create_legacy(i, handler->name, handler->pid) < 0) {
+		ERROR("failed to create legacy ns cgroups for '%s'", handler->name);
+		return false;
 	}
+	return true;
+}
 
-out:
-	close(fd);
-	return ret;
+static char *cgfs_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+{
+	return lxc_cgroup_get_hierarchy_path_handler(subsystem, handler);
 }
 
-int freeze_unfreeze(const char *name, int freeze, const char *lxcpath)
+static struct cgroup_ops cgfs_ops = {
+	.destroy = cgfs_destroy,
+	.init = cgfs_init,
+	.create = cgfs_create,
+	.enter = cgfs_enter,
+	.create_legacy = cgfs_create_legacy,
+	.get_cgroup = cgfs_get_cgroup,
+	.get = lxc_cgroupfs_get,
+	.set = lxc_cgroupfs_set,
+	.name = "cgroupfs",
+};
+static void init_cg_ops(void)
 {
-	char *cgabspath;
-	int ret;
+	if (!use_cgmanager)
+		return;
+	if (cgmanager_initialized)
+		return;
+	if (!lxc_init_cgmanager()) {
+		ERROR("Could not contact cgroup manager, falling back to cgroupfs");
+		active_cg_ops = &cgfs_ops;
+	}
+}
 
-	cgabspath = lxc_cgroup_get_hierarchy_abs_path("freezer", name, lxcpath);
-	if (!cgabspath)
-		return -1;
+/*
+ * These are the backend-independent cgroup handlers for container
+ * start and stop
+ */
 
-	ret = do_unfreeze(cgabspath, freeze, name, lxcpath);
-	free(cgabspath);
-	return ret;
+/* Free all cgroup info held by the handler */
+void cgroup_destroy(struct lxc_handler *handler)
+{
+	if (!handler->cgroup_info)
+		return;
+	if (active_cg_ops)
+		active_cg_ops->destroy(handler);
 }
 
-lxc_state_t freezer_state(const char *name, const char *lxcpath)
+/*
+ * Allocate a lxc_cgroup_info for the active cgroup
+ * backend, and assign it to the handler
+ */
+bool cgroup_init(struct lxc_handler *handler)
 {
-	char *cgabspath = NULL;
-	char freezer[MAXPATHLEN];
-	char status[MAXPATHLEN];
-	FILE *file;
-	int ret;
+	init_cg_ops();
+	handler->cgroup_info = malloc(sizeof(struct lxc_cgroup_info));
+	if (!handler->cgroup_info)
+		return false;
+	memset(handler->cgroup_info, 0, sizeof(struct lxc_cgroup_info));
+	/* if we are running as root, use system cgroup pattern, otherwise
+	 * just create a cgroup under the current one. But also fall back to
+	 * that if for some reason reading the configuration fails and no
+	 * default value is available
+	 */
+	if (geteuid() == 0)
+		handler->cgroup_info->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+	if (!handler->cgroup_info->cgroup_pattern)
+		handler->cgroup_info->cgroup_pattern = "%n";
 
-	cgabspath = lxc_cgroup_get_hierarchy_abs_path("freezer", name, lxcpath);
-	if (!cgabspath)
-		return -1;
+	return active_cg_ops->init(handler);
+}
 
-	ret = snprintf(freezer, MAXPATHLEN, "%s/freezer.state", cgabspath);
-	if (ret < 0 || ret >= MAXPATHLEN)
-		goto out;
+/* Create the container cgroups for all requested controllers */
+bool cgroup_create(struct lxc_handler *handler)
+{
+	return active_cg_ops->create(handler);
+}
 
-	file = fopen(freezer, "r");
-	if (!file) {
-		ret = -1;
-		goto out;
-	}
+/*
+ * Set up per-controller configuration excluding the devices
+ * cgroup
+ */
+bool cgroup_setup_without_devices(struct lxc_handler *handler)
+{
+	return do_setup_cgroup(handler, &handler->conf->cgroup, false) == 0;
+}
 
-	ret = fscanf(file, "%s", status);
-	fclose(file);
+/* Set up the devices cgroup configuration for the container */
+bool cgroup_setup_devices(struct lxc_handler *handler)
+{
+	return do_setup_cgroup(handler, &handler->conf->cgroup, true) == 0;
+}
 
-	if (ret == EOF) {
-		SYSERROR("failed to read %s", freezer);
-		ret = -1;
-		goto out;
-	}
+/*
+ * Enter the container init into its new cgroups for all
+ * requested controllers */
+bool cgroup_enter(struct lxc_handler *handler)
+{
+	return active_cg_ops->enter(handler);
+}
 
-	ret = lxc_str2state(status);
+bool cgroup_create_legacy(struct lxc_handler *handler)
+{
+	if (active_cg_ops->create_legacy)
+		return active_cg_ops->create_legacy(handler);
+	return true;
+}
 
-out:
-	free(cgabspath);
-	return ret;
+char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+{
+	return active_cg_ops->get_cgroup(handler, subsystem);
 }
 
+int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	init_cg_ops();
+	return active_cg_ops->set(filename, value, name, lxcpath);
+}
+
+int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	init_cg_ops();
+	return active_cg_ops->get(filename, value, len, name, lxcpath);
+}
diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
index 3aab12d..8316e79 100644
--- a/src/lxc/cgroup.h
+++ b/src/lxc/cgroup.h
@@ -72,6 +72,9 @@ struct cgroup_mount_point {
  * cgroup_process_info: describes the membership of a
  *                      process to the different cgroup
  *                      hierarchies
+ *
+ * Note this is the per-process info tracked by the cgfs_ops.
+ * This is not used with cgmanager.
  */
 struct cgroup_process_info {
 	struct cgroup_process_info *next;
@@ -121,22 +124,19 @@ extern int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const
 /* get the cgroup membership of a given container */
 extern struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data);
 
-/* move a processs to the cgroups specified by the membership */
-extern int lxc_cgroup_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub);
+/* move a processs to the cgroups specified by the membership TODO - deprecated, switch users to cgroup_enter() */
+extern int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub);
 
 /* free process membership information */
 extern void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
 extern void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info);
 
 struct lxc_handler;
-extern char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct lxc_handler *handler);
 extern char *lxc_cgroup_get_hierarchy_path(const char *subsystem, const char *name, const char *lxcpath);
 extern char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lxc_handler *handler);
 extern char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath);
 extern int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler);
 extern int lxc_cgroup_get_handler(const char *filename, char *value, size_t len, struct lxc_handler *handler);
-extern int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath);
-extern int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
 
 /*
  * lxc_cgroup_path_get: Get the absolute pathname for a cgroup
@@ -162,12 +162,57 @@ struct lxc_list;
 extern int lxc_setup_cgroup_without_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings);
 extern int lxc_setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings);
 
-extern int lxc_setup_mount_cgroup(const char *root, struct cgroup_process_info *base_info, int type);
-
 extern int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler);
 
-extern int do_unfreeze(const char *nsgroup, int freeze, const char *name, const char *lxcpath);
+extern int do_unfreeze(int freeze, const char *name, const char *lxcpath);
 extern int freeze_unfreeze(const char *name, int freeze, const char *lxcpath);
 extern const char *lxc_state2str(lxc_state_t state);
 extern lxc_state_t freezer_state(const char *name, const char *lxcpath);
+/* per-backend cgroup hooks */
+struct cgroup_ops {
+	void (*destroy)(struct lxc_handler *handler);
+	bool (*init)(struct lxc_handler *handler);
+	bool (*create)(struct lxc_handler *handler);
+	bool (*enter)(struct lxc_handler *handler);
+	bool (*create_legacy)(struct lxc_handler *handler);
+	char *(*get_cgroup)(struct lxc_handler *handler, const char *subsystem);
+	int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
+	int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
+	const char *name;
+};
+
+/*
+ * cgroup-related data for backend use in start/stop of a
+ * container.  This is tacked to the lxc_handler.
+ */
+struct lxc_cgroup_info {
+	/* handlers to actually do the cgroup stuff */
+	struct cgroup_ops *ops;
+	/* extra data for the cgroup_ops, i.e. mountpoints for fs backend */
+	void *data;
+	const char *cgroup_pattern;
+};
+
+extern int lxc_setup_mount_cgroup(const char *root, struct lxc_cgroup_info *base_info, int type);
+
+struct cgfs_data {
+	struct cgroup_meta_data *meta;
+	struct cgroup_process_info *info;
+};
+
+/*
+ * backend-independent cgroup handlers
+ */
+extern void cgroup_destroy(struct lxc_handler *handler);
+extern bool cgroup_init(struct lxc_handler *handler);
+extern bool cgroup_create(struct lxc_handler *handler);
+extern bool cgroup_setup_without_devices(struct lxc_handler *handler);
+extern bool cgroup_setup_devices(struct lxc_handler *handler);
+extern bool cgroup_enter(struct lxc_handler *handler);
+extern void cgroup_cleanup(struct lxc_handler *handler);
+extern bool cgroup_create_legacy(struct lxc_handler *handler);
+extern char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
+extern int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath);
+extern int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
+
 #endif
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index e993f2e..29aa905 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -435,7 +435,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
 	if (req->datalen < 1)
 		return -1;
 
-	path = lxc_cgroup_get_hierarchy_path_handler(req->data, handler);
+	path = cgroup_get_cgroup(handler, req->data);
 	if (!path)
 		return -1;
 	rsp.datalen = strlen(path) + 1,
@@ -591,17 +591,10 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
 	memset(&rsp, 0, sizeof(rsp));
 	rsp.ret = kill(handler->pid, stopsignal);
 	if (!rsp.ret) {
-		char *path = lxc_cgroup_get_hierarchy_path_handler("freezer", handler);
-		if (!path) {
-			ERROR("container %s:%s is not in a freezer cgroup",
-				handler->lxcpath, handler->name);
-			return 0;
-		}
-		ret = lxc_unfreeze_bypath(path);
+		ret = lxc_unfreeze(handler->name, handler->lxcpath);
 		if (!ret)
 			return 0;
-
-		ERROR("failed to unfreeze container");
+		ERROR("Failed to unfreeze %s:%s", handler->lxcpath, handler->name);
 		rsp.ret = ret;
 	}
 
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 7e0eddd..6552af6 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -646,7 +646,7 @@ int pin_rootfs(const char *rootfs)
 	return fd;
 }
 
-static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct cgroup_process_info *cgroup_info)
+static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cgroup_info *cgroup_info)
 {
 	int r;
 	size_t i;
@@ -3458,8 +3458,14 @@ static int check_autodev( const char *rootfs, void *data )
 	return 0;
 }
 
-int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath, struct cgroup_process_info *cgroup_info, void *data)
+int lxc_setup(struct lxc_handler *handler)
 {
+	const char *name = handler->name;
+	struct lxc_conf *lxc_conf = handler->conf;
+	const char *lxcpath = handler->lxcpath;
+	void *data = handler->data;
+	struct lxc_cgroup_info *cgroup_info = handler->cgroup_info;
+
 	if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
 		if (setup_utsname(lxc_conf->utsname)) {
 			ERROR("failed to setup the utsname for '%s'", name);
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 8efd0f3..a0ce3f7 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -366,10 +366,7 @@ extern int lxc_clear_groups(struct lxc_conf *c);
  */
 
 struct cgroup_process_info;
-extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf,
-			const char *lxcpath,
-			struct cgroup_process_info *cgroup_info,
-			void *data);
+extern int lxc_setup(struct lxc_handler *handler);
 
 extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
 
diff --git a/src/lxc/freezer.c b/src/lxc/freezer.c
index 53e9f64..c33a727 100644
--- a/src/lxc/freezer.c
+++ b/src/lxc/freezer.c
@@ -50,17 +50,3 @@ int lxc_unfreeze(const char *name, const char *lxcpath)
 {
 	return freeze_unfreeze(name, 0, lxcpath);
 }
-
-int lxc_unfreeze_bypath(const char *cgrelpath)
-{
-	char *cgabspath;
-	int ret;
-
-	cgabspath = lxc_cgroup_find_abs_path("freezer", cgrelpath, true, NULL);
-	if (!cgabspath)
-		return -1;
-
-	ret = do_unfreeze(cgabspath, 0, NULL, NULL);
-	free(cgabspath);
-	return ret;
-}
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index d048cf2..0682f86 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
@@ -123,14 +123,6 @@ extern int lxc_freeze(const char *name, const char *lxcpath);
 extern int lxc_unfreeze(const char *name, const char *lxcpath);
 
 /*
- * Unfreeze all previously frozen tasks.
- * This is the function to use from inside the monitor
- * @name : the name of the container
- * Return 0 on sucess, < 0 otherwise
- */
-extern int lxc_unfreeze_bypath(const char *cgpath);
-
-/*
  * Retrieve the container state
  * @name : the name of the container
  * Returns the state of the container on success, < 0 otherwise
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 6c07e43..441d0f4 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -457,10 +457,7 @@ static void lxc_fini(const char *name, struct lxc_handler *handler)
 	close(handler->conf->maincmd_fd);
 	handler->conf->maincmd_fd = -1;
 	free(handler->name);
-	if (handler->cgroup) {
-		lxc_cgroup_process_info_free_and_remove(handler->cgroup);
-		handler->cgroup = NULL;
-	}
+	cgroup_destroy(handler);
 	free(handler);
 }
 
@@ -602,7 +599,7 @@ static int do_start(void *data)
 	#endif
 
 	/* Setup the container, ip, names, utsname, ... */
-	if (lxc_setup(handler->name, handler->conf, handler->lxcpath, handler->cgroup, handler->data) ){
+	if (lxc_setup(handler)) {
 		ERROR("failed to setup the container");
 		goto out_warn_father;
 	}
@@ -690,8 +687,6 @@ static int lxc_spawn(struct lxc_handler *handler)
 {
 	int failed_before_rename = 0;
 	const char *name = handler->name;
-	struct cgroup_meta_data *cgroup_meta = NULL;
-	const char *cgroup_pattern = NULL;
 	int saved_ns_fd[LXC_NS_MAX];
 	int preserve_mask = 0, i;
 
@@ -755,27 +750,13 @@ static int lxc_spawn(struct lxc_handler *handler)
 	}
 
 
-	cgroup_meta = lxc_cgroup_load_meta();
-	if (!cgroup_meta) {
-		ERROR("failed to detect cgroup metadata");
+	if (!cgroup_init(handler)) {
+		ERROR("failed initializing cgroup support");
 		goto out_delete_net;
 	}
 
-	/* if we are running as root, use system cgroup pattern, otherwise
-	 * just create a cgroup under the current one. But also fall back to
-	 * that if for some reason reading the configuration fails and no
-	 * default value is available
-	 */
-	if (getuid() == 0)
-		cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-	if (!cgroup_pattern)
-		cgroup_pattern = "%n";
-
-	/* Create cgroup before doing clone(), so the child will know from
-	 * handler which cgroup it is going to be put in later.
-	 */
-	if ((handler->cgroup = lxc_cgroup_create(name, cgroup_pattern, cgroup_meta, NULL)) == NULL) {
-		ERROR("failed to create cgroups for '%s'", name);
+	if (!cgroup_create(handler)) {
+		ERROR("failed creating cgroups");
 		goto out_delete_net;
 	}
 
@@ -808,20 +789,16 @@ static int lxc_spawn(struct lxc_handler *handler)
 	if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
 		failed_before_rename = 1;
 
-	/* In case there is still legacy ns cgroup support in the kernel.
-	 * Should be removed at some later point in time.
-	 */
-	if (lxc_cgroup_create_legacy(handler->cgroup, name, handler->pid) < 0) {
-		ERROR("failed to create legacy ns cgroups for '%s'", name);
+	if (!cgroup_create_legacy(handler)) {
+		ERROR("failed to setup the legacy cgroups for %s", name);
 		goto out_delete_net;
 	}
-
-	if (lxc_setup_cgroup_without_devices(handler, &handler->conf->cgroup)) {
+	if (!cgroup_setup_without_devices(handler)) {
 		ERROR("failed to setup the cgroups for '%s'", name);
 		goto out_delete_net;
 	}
 
-	if (lxc_cgroup_enter(handler->cgroup, handler->pid, false) < 0)
+	if (!cgroup_enter(handler))
 		goto out_delete_net;
 
 	if (failed_before_rename)
@@ -851,7 +828,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 	if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE))
 		goto out_delete_net;
 
-	if (lxc_setup_cgroup_devices(handler, &handler->conf->cgroup)) {
+	if (!cgroup_setup_devices(handler)) {
 		ERROR("failed to setup the devices cgroup for '%s'", name);
 		goto out_delete_net;
 	}
@@ -878,7 +855,6 @@ static int lxc_spawn(struct lxc_handler *handler)
 		goto out_abort;
 	}
 
-	lxc_cgroup_put_meta(cgroup_meta);
 	lxc_sync_fini(handler);
 
 	return 0;
@@ -887,7 +863,6 @@ out_delete_net:
 	if (handler->clone_flags & CLONE_NEWNET)
 		lxc_delete_network(handler);
 out_abort:
-	lxc_cgroup_put_meta(cgroup_meta);
 	lxc_abort(name, handler);
 	lxc_sync_fini(handler);
 	if (handler->pinfd >= 0) {
diff --git a/src/lxc/start.h b/src/lxc/start.h
index 7d4ae59..c30c661 100644
--- a/src/lxc/start.h
+++ b/src/lxc/start.h
@@ -70,7 +70,7 @@ struct lxc_handler {
 	int sv[2];
 	int pinfd;
 	const char *lxcpath;
-	struct cgroup_process_info *cgroup;
+	struct lxc_cgroup_info *cgroup_info;
 };
 
 extern struct lxc_handler *lxc_init(const char *name, struct lxc_conf *, const char *);
-- 
1.8.5.2



More information about the lxc-devel mailing list