[lxc-devel] [PATCH 2/2] split cgroup handling into discrete backends

Dwight Engen dwight.engen at oracle.com
Wed Feb 5 21:59:26 UTC 2014


- refactor cgroup into two backends, the classic cgfs driver and the new
  cgmanager. Instead of lxc_handler knowing about the internals of each,
  have it just store an opaque pointer to a struct that is private to
  each backend.

- rename a couple of cgroup functions for consistency: those that are
  considered an API (ie. exported by lxc.h) begin with lxc_ and those that
  are not are just cgroup_*

- made as many backend routines static as possible, only cg*_ops_init is
  exported

- made a nrtasks op which is needed by the utmp code for monitoring
  container shutdown, currently only implemented for the cgfs backend

Signed-off-by: Dwight Engen <dwight.engen at oracle.com>
---
 src/lxc/Makefile.am |   3 +-
 src/lxc/attach.c    |   2 +-
 src/lxc/cgfs.c      | 524 +++++++++++++++++++++-------------------------------
 src/lxc/cgmanager.c | 272 ++++++++++++++++-----------
 src/lxc/cgroup.c    | 169 +++++++++++++++++
 src/lxc/cgroup.h    | 207 +++------------------
 src/lxc/commands.c  |  11 +-
 src/lxc/conf.c      |  12 +-
 src/lxc/freezer.c   |  41 +++-
 src/lxc/lxc.h       |  11 --
 src/lxc/lxcutmp.c   |   2 +-
 src/lxc/start.h     |   2 +-
 src/lxc/state.c     |   2 +
 src/tests/cgpath.c  |  28 +--
 14 files changed, 631 insertions(+), 655 deletions(-)
 create mode 100644 src/lxc/cgroup.c

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index b4aa924..19511a4 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -62,7 +62,8 @@ liblxc_so_SOURCES = \
 	freezer.c \
 	error.h error.c \
 	parse.c parse.h \
-	cgfs.c cgroup.h \
+	cgfs.c \
+	cgroup.c cgroup.h \
 	lxc.h \
 	utils.c utils.h \
 	sync.c sync.h \
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 5c4adcd..8782652 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -699,7 +699,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
 
 		/* attach to cgroup, if requested */
 		if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
-			if (!lxc_cgroup_attach(name, lxcpath, pid))
+			if (!cgroup_attach(name, lxcpath, pid))
 				goto cleanup_error;
 		}
 
diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c
index c23b784..f576ba1 100644
--- a/src/lxc/cgfs.c
+++ b/src/lxc/cgfs.c
@@ -55,7 +55,75 @@
 #include <mntent.h>
 #endif
 
-lxc_log_define(lxc_cgroup, lxc);
+struct cgroup_hierarchy;
+struct cgroup_meta_data;
+struct cgroup_mount_point;
+
+/*
+ * cgroup_meta_data: the metadata about the cgroup infrastructure on this
+ *                   host
+ */
+struct cgroup_meta_data {
+	ptrdiff_t ref; /* simple refcount */
+	struct cgroup_hierarchy **hierarchies;
+	struct cgroup_mount_point **mount_points;
+	int maximum_hierarchy;
+};
+
+/*
+ * cgroup_hierarchy: describes a single cgroup hierarchy
+ *                   (may have multiple mount points)
+ */
+struct cgroup_hierarchy {
+	int index;
+	bool used; /* false if the hierarchy should be ignored by lxc */
+	char **subsystems;
+	struct cgroup_mount_point *rw_absolute_mount_point;
+	struct cgroup_mount_point *ro_absolute_mount_point;
+	struct cgroup_mount_point **all_mount_points;
+	size_t all_mount_point_capacity;
+};
+
+/*
+ * cgroup_mount_point: a mount point to where a hierarchy
+ *                     is mounted to
+ */
+struct cgroup_mount_point {
+	struct cgroup_hierarchy *hierarchy;
+	char *mount_point;
+	char *mount_prefix;
+	bool read_only;
+	bool need_cpuset_init;
+};
+
+/*
+ * 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;
+	struct cgroup_meta_data *meta_ref;
+	struct cgroup_hierarchy *hierarchy;
+	char *cgroup_path;
+	char *cgroup_path_sub;
+	char **created_paths;
+	size_t created_paths_capacity;
+	size_t created_paths_count;
+	struct cgroup_mount_point *designated_mount_point;
+};
+
+struct cgfs_data {
+	char *name;
+	const char *cgroup_pattern;
+	struct cgroup_meta_data *meta;
+	struct cgroup_process_info *info;
+};
+
+lxc_log_define(lxc_cgfs, lxc);
 
 static struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str, struct cgroup_meta_data *meta);
 static char **subsystems_from_mount_options(const char *mount_options, char **kernel_list);
@@ -68,27 +136,22 @@ static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *
 static struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem);
 static int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len);
 static int do_cgroup_set(const char *cgroup_path, const char *sub_filename, const char *value);
-static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h, char *v, bool for_allow);
-static int do_setup_cgroup_limits(struct lxc_handler *h, struct lxc_list *cgroup_settings, bool do_devices);
+static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d, char *v, bool for_allow);
+static int do_setup_cgroup_limits(struct cgfs_data *d, struct lxc_list *cgroup_settings, bool do_devices);
 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 bool init_cpuset_if_needed(struct cgroup_mount_point *mp, const char *path);
 
+static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist);
+static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data);
+static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data);
+
+/* free process membership information */
+static void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
+static void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info);
+
 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)
 {
@@ -159,7 +222,7 @@ static int cgroup_rmdir(char *dirname)
 	return failed ? -1 : 0;
 }
 
-struct cgroup_meta_data *lxc_cgroup_load_meta()
+static struct cgroup_meta_data *lxc_cgroup_load_meta()
 {
 	const char *cgroup_use = NULL;
 	char **cgroup_use_list = NULL;
@@ -184,7 +247,7 @@ struct cgroup_meta_data *lxc_cgroup_load_meta()
 }
 
 /* Step 1: determine all kernel subsystems */
-bool find_cgroup_subsystems(char ***kernel_subsystems)
+static bool find_cgroup_subsystems(char ***kernel_subsystems)
 {
 	FILE *proc_cgroups;
 	bool bret = false;
@@ -470,7 +533,7 @@ out:
 	return bret;
 }
 
-struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
+static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
 {
 	bool all_kernel_subsystems = true;
 	bool all_named_subsystems = false;
@@ -526,13 +589,13 @@ out_error:
 	return NULL;
 }
 
-struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
+static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
 {
 	meta_data->ref++;
 	return meta_data;
 }
 
-struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
+static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
 {
 	size_t i;
 	if (!meta_data)
@@ -549,7 +612,7 @@ struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
 	return NULL;
 }
 
-struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
+static struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
 {
 	size_t i;
 	for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
@@ -560,7 +623,7 @@ struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta
 	return NULL;
 }
 
-struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
+static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
 {
 	struct cgroup_mount_point **mps;
 	struct cgroup_mount_point *current_result = NULL;
@@ -600,7 +663,7 @@ struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *
 	return current_result;
 }
 
-char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
+static char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
 {
 	struct cgroup_meta_data *meta_data;
 	struct cgroup_hierarchy *h;
@@ -634,19 +697,19 @@ out_error:
 	return NULL;
 }
 
-struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
+static struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
 {
 	char pid_buf[32];
 	snprintf(pid_buf, 32, "/proc/%lu/cgroup", (unsigned long)pid);
 	return lxc_cgroup_process_info_getx(pid_buf, meta);
 }
 
-struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
+static struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
 {
 	return lxc_cgroup_process_info_get(1, meta);
 }
 
-struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
+static struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
 {
 	struct cgroup_process_info *i;
 	i = lxc_cgroup_process_info_getx("/proc/self/cgroup", meta);
@@ -724,7 +787,7 @@ static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, p
 }
 
 /* create a new cgroup */
-struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
+static 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;
@@ -817,7 +880,7 @@ struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *pa
 		}
 
 		goto find_name_on_this_level;
-	
+
 	cleanup_name_on_this_level:
 		/* This is reached if we found a name clash.
 		 * In that case, remove the cgroup from all previous hierarchies
@@ -836,7 +899,7 @@ struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *pa
 		current_component = current_subpath = NULL;
 		/* try again with another suffix */
 		++suffix;
-	
+
 	find_name_on_this_level:
 		/* determine name of the path component we should create */
 		if (contains_name && suffix > 0) {
@@ -937,7 +1000,7 @@ struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *pa
 			free(current_component);
 		current_component = current_subpath = NULL;
 		continue;
-	
+
 	cleanup_from_error:
 		/* called if an error occured in the loop, so we
 		 * do some additional cleanup here
@@ -985,7 +1048,7 @@ out_initial_error:
 	return NULL;
 }
 
-int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
+static int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
 {
 	struct cgroup_process_info *info_ptr;
 	int r;
@@ -1016,7 +1079,7 @@ int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *
 }
 
 /* get the cgroup membership of a given container */
-struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
+static struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
 {
 	struct cgroup_process_info *result = NULL;
 	int saved_errno = 0;
@@ -1064,7 +1127,7 @@ out_error:
 }
 
 /* move a processs to the cgroups specified by the membership */
-int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
+static int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
 {
 	char pid_buf[32];
 	char *cgroup_tasks_fn;
@@ -1148,9 +1211,8 @@ void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
 	lxc_cgroup_process_info_free_and_remove(next);
 }
 
-static char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct lxc_handler *handler)
+static char *lxc_cgroup_get_hierarchy_path_data(const char *subsystem, struct cgfs_data *d)
 {
-	struct cgfs_data *d = handler->cgroup_info->data;
 	struct cgroup_process_info *info = d->info;
 	info = find_info_for_subsystem(info, subsystem);
 	if (!info)
@@ -1158,14 +1220,8 @@ static char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct
 	return info->cgroup_path;
 }
 
-char *lxc_cgroup_get_hierarchy_path(const char *subsystem, const char *name, const char *lxcpath)
-{
-	return lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
-}
-
-char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lxc_handler *handler)
+static char *lxc_cgroup_get_hierarchy_abs_path_data(const char *subsystem, struct cgfs_data *d)
 {
-	struct cgfs_data *d = handler->cgroup_info->data;
 	struct cgroup_process_info *info = d->info;
 	struct cgroup_mount_point *mp = NULL;
 
@@ -1182,7 +1238,7 @@ char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lx
 	return cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
 }
 
-char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
+static char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
 {
 	struct cgroup_meta_data *meta;
 	struct cgroup_process_info *base_info, *info;
@@ -1214,7 +1270,7 @@ out1:
 	return result;
 }
 
-int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler)
+static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfs_data *d)
 {
 	char *subsystem = NULL, *p, *path;
 	int ret = -1;
@@ -1224,7 +1280,7 @@ int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_h
 	if ((p = index(subsystem, '.')) != NULL)
 		*p = '\0';
 
-	path = lxc_cgroup_get_hierarchy_abs_path_handler(subsystem, handler);
+	path = lxc_cgroup_get_hierarchy_abs_path_data(subsystem, d);
 	if (path) {
 		ret = do_cgroup_set(path, filename, value);
 		free(path);
@@ -1232,25 +1288,7 @@ int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_h
 	return ret;
 }
 
-int lxc_cgroup_get_handler(const char *filename, char *value, size_t len, struct lxc_handler *handler)
-{
-	char *subsystem = NULL, *p, *path;
-	int ret = -1;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = index(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	path = lxc_cgroup_get_hierarchy_abs_path_handler(subsystem, handler);
-	if (path) {
-		ret = do_cgroup_get(path, filename, value, len);
-		free(path);
-	}
-	return ret;
-}
-
-int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+static int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
 {
 	char *subsystem = NULL, *p, *path;
 	int ret = -1;
@@ -1268,7 +1306,7 @@ int lxc_cgroupfs_set(const char *filename, const char *value, const char *name,
 	return ret;
 }
 
-int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+static 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;
@@ -1286,48 +1324,7 @@ int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *
 	return ret;
 }
 
-/*
- * lxc_cgroup_path_get: Get the absolute pathname for a cgroup
- * file for a running container.
- *
- * @filename  : the file of interest (e.g. "freezer.state") or
- *              the subsystem name (e.g. "freezer") in which case
- *              the directory where the cgroup may be modified
- *              will be returned
- * @name      : name of container to connect to
- * @lxcpath   : the lxcpath in which the container is running
- *
- * This is the exported function, which determines cgpath from the
- * lxc-start of the @name container running in @lxcpath.
- *
- * Returns path on success, NULL on error. The caller must free()
- * the returned path.
- */
-char *lxc_cgroup_path_get(const char *filename, const char *name,
-                          const char *lxcpath)
-{
-	char *subsystem = NULL, *longer_file = NULL, *p, *group, *path;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = index(subsystem, '.')) != NULL) {
-		*p = '\0';
-		longer_file = alloca(strlen(filename) + 2);
-		longer_file[0] = '/';
-		strcpy(longer_file + 1, filename);
-	}
-
-	group = lxc_cgroup_get_hierarchy_path(subsystem, name, lxcpath);
-	if (!group)
-		return NULL;
-
-	path = lxc_cgroup_find_abs_path(subsystem, group, true, p ? longer_file : NULL);
-	free(group);
-	return path;
-}
-
-static bool cgroupfs_mount_cgroup(const char *root,
-		struct lxc_cgroup_info *cgroup_info, int type)
+static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
 {
 	size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup");
 	char *path = NULL;
@@ -1339,9 +1336,9 @@ static bool cgroupfs_mount_cgroup(const char *root,
 	struct cgroup_process_info *info, *base_info;
 	int r, saved_errno = 0;
 
-	init_cg_ops();
-
-	cgfs_d = cgroup_info->data;
+	cgfs_d = hdata;
+	if (!cgfs_d)
+		return false;
 	base_info = cgfs_d->info;
 
 	if (type < LXC_AUTO_CGROUP_RO || type > LXC_AUTO_CGROUP_FULL_MIXED) {
@@ -1510,14 +1507,20 @@ out_error:
 	return false;
 }
 
-int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler)
+static int cgfs_nrtasks(void *hdata)
 {
-	struct cgfs_data *d = handler->cgroup_info->data;
-	struct cgroup_process_info *info = d->info;
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *info;
 	struct cgroup_mount_point *mp = NULL;
 	char *abs_path = NULL;
 	int ret;
 
+	if (!d) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	info = d->info;
 	if (!info) {
 		errno = ENOENT;
 		return -1;
@@ -1842,7 +1845,7 @@ static int do_cgroup_set(const char *cgroup_path, const char *sub_filename,
 	return ret;
 }
 
-static int do_setup_cgroup_limits(struct lxc_handler *h,
+static int do_setup_cgroup_limits(struct cgfs_data *d,
 			   struct lxc_list *cgroup_settings, bool do_devices)
 {
 	struct lxc_list *iterator;
@@ -1857,14 +1860,14 @@ static int do_setup_cgroup_limits(struct lxc_handler *h,
 
 		if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
 			if (strcmp(cg->subsystem, "devices.deny") == 0 &&
-					cgroup_devices_has_allow_or_deny(h, cg->value, false))
+					cgroup_devices_has_allow_or_deny(d, cg->value, false))
 				continue;
 			if (strcmp(cg->subsystem, "devices.allow") == 0 &&
-					cgroup_devices_has_allow_or_deny(h, cg->value, true))
+					cgroup_devices_has_allow_or_deny(d, cg->value, true))
 				continue;
-			if (lxc_cgroup_set_handler(cg->subsystem, cg->value, h)) {
+			if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
 				ERROR("Error setting %s to %s for %s\n",
-				      cg->subsystem, cg->value, h->name);
+				      cg->subsystem, cg->value, d->name);
 				goto out;
 			}
 		}
@@ -1878,7 +1881,7 @@ out:
 	return ret;
 }
 
-static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h,
+static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d,
 					     char *v, bool for_allow)
 {
 	char *path;
@@ -1898,7 +1901,7 @@ static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h,
 	if (!for_allow && strcmp(v, "a") != 0 && strcmp(v, "a *:* rwm") != 0)
 		return false;
 
-	parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_handler("devices", h);
+	parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_data("devices", d);
 	if (!parts[0])
 		return false;
 	path = lxc_string_join("/", parts, false);
@@ -2167,124 +2170,127 @@ static bool init_cpuset_if_needed(struct cgroup_mount_point *mp,
 		do_init_cpuset_file(mp, path, "/cpuset.mems") );
 }
 
-extern void lxc_monitor_send_state(const char *name, lxc_state_t state,
-			    const char *lxcpath);
-int do_unfreeze(int freeze, const char *name, const char *lxcpath)
+struct cgroup_ops *cgfs_ops_init(void)
 {
-	char v[100];
-	const char *state = freeze ? "FROZEN" : "THAWED";
-
-	if (lxc_cgroup_set("freezer.state", state, name, lxcpath) < 0) {
-		ERROR("Failed to freeze %s:%s", lxcpath, name);
-		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);
-	}
+	return &cgfs_ops;
 }
 
-int freeze_unfreeze(const char *name, int freeze, const char *lxcpath)
+static void *cgfs_init(const char *name)
 {
-	return do_unfreeze(freeze, name, lxcpath);
-}
+	struct cgfs_data *d;
 
-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)
-		return -1;
+	d = malloc(sizeof(*d));
+	if (!d)
+		return NULL;
 
-	if (v[strlen(v)-1] == '\n')
-		v[strlen(v)-1] = '\0';
-	return lxc_str2state(v);
+	memset(d, 0, sizeof(*d));
+	d->name = strdup(name);
+	if (!d->name)
+		goto err1;
+
+	/* 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)
+		d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+	if (!d->cgroup_pattern)
+		d->cgroup_pattern = "%n";
+
+	d->meta = lxc_cgroup_load_meta();
+	if (!d->meta) {
+		ERROR("cgroupfs failed to detect cgroup metadata");
+		goto err2;
+	}
+	return d;
+
+err2:
+	free(d->name);
+err1:
+	free(d);
+	return NULL;
 }
 
-static void cgfs_destroy(struct lxc_handler *handler)
+static void cgfs_destroy(void *hdata)
 {
-	struct cgfs_data *d = handler->cgroup_info->data;
+	struct cgfs_data *d = hdata;
+
 	if (!d)
 		return;
+	if (d->name)
+		free(d->name);
 	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;
 }
 
-static inline bool cgfs_init(struct lxc_handler *handler)
+static inline bool cgfs_create(void *hdata)
 {
-	struct cgfs_data *d = malloc(sizeof(*d));
-	if (!d)
-		return false;
-	d->info = NULL;
-	d->meta = lxc_cgroup_load_meta();
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *i;
+	struct cgroup_meta_data *md;
 
-	if (!d->meta) {
-		ERROR("cgroupfs failed to detect cgroup metadata");
-		free(d);
+	if (!d)
 		return false;
-	}
-	handler->cgroup_info->data = d;
-	return true;
-}
-
-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);
+	md = d->meta;
+	i = lxc_cgroupfs_create(d->name, d->cgroup_pattern, md, NULL);
 	if (!i)
 		return false;
 	d->info = i;
 	return true;
 }
 
-static inline bool cgfs_enter(struct lxc_handler *handler)
+static inline bool cgfs_enter(void *hdata, pid_t pid)
 {
-	struct cgfs_data *d = handler->cgroup_info->data;
-	struct cgroup_process_info *i = d->info;
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *i;
 	int ret;
-	
-	ret = lxc_cgroupfs_enter(i, handler->pid, false);
+
+	if (!d)
+		return false;
+	i = d->info;
+	ret = lxc_cgroupfs_enter(i, pid, false);
 
 	return ret == 0;
 }
 
-static inline bool cgfs_create_legacy(struct lxc_handler *handler)
+static inline bool cgfs_create_legacy(void *hdata, pid_t pid)
 {
-	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);
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *i;
+
+	if (!d)
+		return false;
+	i = d->info;
+	if (lxc_cgroup_create_legacy(i, d->name, pid) < 0) {
+		ERROR("failed to create legacy ns cgroups for '%s'", d->name);
 		return false;
 	}
 	return true;
 }
 
-static char *cgfs_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+static const char *cgfs_get_cgroup(void *hdata, const char *subsystem)
 {
-	return lxc_cgroup_get_hierarchy_path_handler(subsystem, handler);
+	struct cgfs_data *d = hdata;
+
+	if (!d)
+		return NULL;
+	return lxc_cgroup_get_hierarchy_path_data(subsystem, d);
 }
 
-static bool cgfs_unfreeze_fromhandler(struct lxc_handler *handler)
+static bool cgfs_unfreeze(void *hdata)
 {
+	struct cgfs_data *d = hdata;
 	char *cgabspath, *cgrelpath;
 	int ret;
 
-	cgrelpath = lxc_cgroup_get_hierarchy_path_handler("freezer", handler);
+	if (!d)
+		return false;
+
+	cgrelpath = lxc_cgroup_get_hierarchy_path_data("freezer", d);
 	cgabspath = lxc_cgroup_find_abs_path("freezer", cgrelpath, true, NULL);
 	if (!cgabspath)
 		return false;
@@ -2294,12 +2300,17 @@ static bool cgfs_unfreeze_fromhandler(struct lxc_handler *handler)
 	return ret == 0;
 }
 
-bool cgroupfs_setup_limits(struct lxc_handler *h, bool with_devices)
+static bool cgroupfs_setup_limits(void *hdata, struct lxc_list *cgroup_conf,
+				  bool with_devices)
 {
-	return do_setup_cgroup_limits(h, &h->conf->cgroup, with_devices) == 0;
+	struct cgfs_data *d = hdata;
+
+	if (!d)
+		return false;
+	return do_setup_cgroup_limits(d, cgroup_conf, with_devices) == 0;
 }
 
-bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
+static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
 {
 	struct cgroup_meta_data *meta_data;
 	struct cgroup_process_info *container_info;
@@ -2328,134 +2339,19 @@ bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
 }
 
 static struct cgroup_ops cgfs_ops = {
-	.destroy = cgfs_destroy,
 	.init = cgfs_init,
+	.destroy = cgfs_destroy,
 	.create = cgfs_create,
 	.enter = cgfs_enter,
 	.create_legacy = cgfs_create_legacy,
 	.get_cgroup = cgfs_get_cgroup,
 	.get = lxc_cgroupfs_get,
 	.set = lxc_cgroupfs_set,
-	.unfreeze_fromhandler = cgfs_unfreeze_fromhandler,
+	.unfreeze = cgfs_unfreeze,
 	.setup_limits = cgroupfs_setup_limits,
 	.name = "cgroupfs",
 	.attach = lxc_cgroupfs_attach,
 	.chown = NULL,
 	.mount_cgroup = cgroupfs_mount_cgroup,
+	.nrtasks = cgfs_nrtasks,
 };
-static void init_cg_ops(void)
-{
-	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;
-	}
-}
-
-/*
- * These are the backend-independent cgroup handlers for container
- * start and stop
- */
-
-/* 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);
-}
-
-/*
- * Allocate a lxc_cgroup_info for the active cgroup
- * backend, and assign it to the handler
- */
-bool cgroup_init(struct lxc_handler *handler)
-{
-	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";
-
-	return active_cg_ops->init(handler);
-}
-
-/* Create the container cgroups for all requested controllers */
-bool cgroup_create(struct lxc_handler *handler)
-{
-	return active_cg_ops->create(handler);
-}
-
-/*
- * 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);
-}
-
-bool cgroup_create_legacy(struct lxc_handler *handler)
-{
-	if (active_cg_ops->create_legacy)
-		return active_cg_ops->create_legacy(handler);
-	return true;
-}
-
-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);
-}
-
-bool lxc_unfreeze_fromhandler(struct lxc_handler *handler)
-{
-	return active_cg_ops->unfreeze_fromhandler(handler);
-}
-
-bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
-{
-	return active_cg_ops->setup_limits(handler, with_devices);
-}
-
-bool cgroup_chown(struct lxc_handler *handler)
-{
-	if (active_cg_ops->chown)
-		return active_cg_ops->chown(handler);
-	return true;
-}
-
-bool lxc_cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
-{
-	init_cg_ops();
-	return active_cg_ops->attach(name, lxcpath, pid);
-}
-
-bool lxc_setup_mount_cgroup(const char *root,
-		struct lxc_cgroup_info *cgroup_info, int type)
-{
-	return active_cg_ops->mount_cgroup(root, cgroup_info, type);
-}
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
index a3faac1..6798b6b 100644
--- a/src/lxc/cgmanager.c
+++ b/src/lxc/cgmanager.c
@@ -58,24 +58,74 @@ lxc_log_define(lxc_cgmanager, lxc);
 #include <nih/alloc.h>
 #include <nih/error.h>
 #include <nih/string.h>
-NihDBusProxy *cgroup_manager = NULL;
 
-extern struct cgroup_ops *active_cg_ops;
-bool cgmanager_initialized = false;
-bool use_cgmanager = true;
+struct cgm_data {
+	char *name;
+	char *cgroup_path;
+	const char *cgroup_pattern;
+};
+
+static NihDBusProxy *cgroup_manager = NULL;
 static struct cgroup_ops cgmanager_ops;
 static int nr_subsystems;
 static char **subsystems;
 
-bool lxc_init_cgmanager(void);
-static void cgmanager_disconnected(DBusConnection *connection)
+#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
+static void cgm_dbus_disconnected(DBusConnection *connection);
+static bool cgm_dbus_connect(void)
+{
+	DBusError dbus_error;
+	DBusConnection *connection;
+	dbus_error_init(&dbus_error);
+
+	connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, cgm_dbus_disconnected);
+	if (!connection) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		DEBUG("Unable to open cgmanager connection at %s: %s", CGMANAGER_DBUS_SOCK,
+			nerr->message);
+		nih_free(nerr);
+		dbus_error_free(&dbus_error);
+		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) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("Error opening cgmanager proxy: %s", nerr->message);
+		nih_free(nerr);
+		return false;
+	}
+
+	// force fd passing negotiation
+	if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("Error pinging cgroup manager: %s", nerr->message);
+		nih_free(nerr);
+	}
+	return true;
+}
+
+static void cgm_dbus_disconnect(void)
+{
+	nih_free(cgroup_manager);
+	cgroup_manager = NULL;
+}
+
+static void cgm_dbus_disconnected(DBusConnection *connection)
 {
 	WARN("Cgroup manager connection was terminated");
 	cgroup_manager = NULL;
-	cgmanager_initialized = false;
-	if (lxc_init_cgmanager()) {
-		cgmanager_initialized = true;
+	if (cgm_dbus_connect()) {
 		INFO("New cgroup manager connection was opened");
+	} else {
+		WARN("Cgroup manager unable to re-open connection");
 	}
 }
 
@@ -115,47 +165,6 @@ static int send_creds(int sock, int rpid, int ruid, int rgid)
 	return 0;
 }
 
-#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) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("Error opening cgmanager connection at %s: %s", CGMANAGER_DBUS_SOCK,
-			nerr->message);
-		nih_free(nerr);
-		dbus_error_free(&dbus_error);
-		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) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("Error opening cgmanager proxy: %s", nerr->message);
-		nih_free(nerr);
-		return false;
-	}
-	active_cg_ops = &cgmanager_ops;
-	// force fd passing negotiation
-	if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("Error pinging cgroup manager: %s", nerr->message);
-		nih_free(nerr);
-	}
-	return true;
-}
-
 static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
 {
 	if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
@@ -341,19 +350,49 @@ static void cgm_remove_cgroup(const char *controller, const char *path)
 		INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
 }
 
-static void cgm_destroy(struct lxc_handler *handler)
+static void *cgm_init(const char *name)
 {
-	char *cgroup_path = handler->cgroup_info->data;
+	struct cgm_data *d;
+
+	d = malloc(sizeof(*d));
+	if (!d)
+		return NULL;
+
+	memset(d, 0, sizeof(*d));
+	d->name = strdup(name);
+	if (!d->name)
+		goto err1;
+
+	/* 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)
+		d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+	if (!d->cgroup_pattern)
+		d->cgroup_pattern = "%n";
+	return d;
+
+err1:
+	free(d);
+	return NULL;
+}
+
+static void cgm_destroy(void *hdata)
+{
+	struct cgm_data *d = hdata;
 	int i;
 
-	if (!cgroup_path)
+	if (!d)
 		return;
-
 	for (i = 0; i < nr_subsystems; i++)
-		cgm_remove_cgroup(subsystems[i], cgroup_path);
+		cgm_remove_cgroup(subsystems[i], d->cgroup_path);
 
-	free(cgroup_path);
-	handler->cgroup_info->data = NULL;
+	free(d->name);
+	if (d->cgroup_path)
+		free(d->cgroup_path);
+	free(d);
 }
 
 /*
@@ -366,19 +405,21 @@ static inline void cleanup_cgroups(char *path)
 		cgm_remove_cgroup(subsystems[i], path);
 }
 
-static inline bool cgm_create(struct lxc_handler *handler)
+static inline bool cgm_create(void *hdata)
 {
+	struct cgm_data *d = hdata;
 	int i, index=0, baselen, ret;
 	int32_t existed;
-	char result[MAXPATHLEN], *tmp;
-	char *cgroup_path = handler->cgroup_info->data;
+	char result[MAXPATHLEN], *tmp, *cgroup_path;
 
+	if (!d)
+		return false;
 // 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);
+	tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
 	if (!tmp)
 		return false;
 	if (strlen(tmp) > MAXPATHLEN)
@@ -415,7 +456,7 @@ again:
 		cleanup_cgroups(tmp);
 		return false;
 	}
-	handler->cgroup_info->data = cgroup_path;
+	d->cgroup_path = cgroup_path;
 	return true;
 next:
 	cleanup_cgroups(tmp);
@@ -454,19 +495,25 @@ static bool do_cgm_enter(pid_t pid, const char *cgroup_path)
 	return true;
 }
 
-static inline bool cgm_enter(struct lxc_handler *handler)
+static inline bool cgm_enter(void *hdata, pid_t pid)
 {
-	char *cgroup_path = handler->cgroup_info->data;
-	return do_cgm_enter(handler->pid, cgroup_path);
+	struct cgm_data *d = hdata;
+
+	if (!d || !d->cgroup_path)
+		return false;
+	return do_cgm_enter(pid, d->cgroup_path);
 }
 
-static char *cgm_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
 {
-	char *cgroup_path = handler->cgroup_info->data;
-	return cgroup_path;
+	struct cgm_data *d = hdata;
+
+	if (!d || !d->cgroup_path)
+		return NULL;
+	return d->cgroup_path;
 }
 
-int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
 {
 	char *result, *controller, *key, *cgroup;
 	size_t newlen;
@@ -531,7 +578,7 @@ static int cgm_do_set(const char *controller, const char *file,
 	return ret;
 }
 
-int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
 {
 	char *controller, *key, *cgroup;
 	int ret;
@@ -555,10 +602,21 @@ int cgm_set(const char *filename, const char *value, const char *name, const cha
 	return ret;
 }
 
+static void free_subsystems(void)
+{
+	int i;
+
+	for (i = 0; i < nr_subsystems; i++)
+		free(subsystems[i]);
+	free(subsystems);
+	subsystems = NULL;
+	nr_subsystems = 0;
+}
+
 static bool collect_subsytems(void)
 {
 	char *line = NULL, *tab1;
-	size_t sz = 0, i;
+	size_t sz = 0;
 	FILE *f;
 
 	if (subsystems) // already initialized
@@ -598,51 +656,62 @@ static bool collect_subsytems(void)
 
 out_free:
 	fclose(f);
-	for (i = 0; i < nr_subsystems; i++)
-		free(subsystems[i]);
-	free(subsystems);
-	subsystems = NULL;
-	nr_subsystems = 0;
+	free_subsystems();
 	return false;
 }
 
-static inline bool cgm_init(struct lxc_handler *handler)
+struct cgroup_ops *cgm_ops_init(void)
 {
 	if (!collect_subsytems())
-		return false;
-	if (geteuid())
-		return true;
+		return NULL;
+	if (!cgm_dbus_connect())
+		goto err1;
+
 	// root;  try to escape to root cgroup
-	return lxc_cgmanager_escape();
+	if (geteuid() == 0 && !lxc_cgmanager_escape())
+		goto err2;
+
+	return &cgmanager_ops;
+
+err2:
+	cgm_dbus_disconnect();
+err1:
+	free_subsystems();
+	return NULL;
 }
 
-static bool cgm_unfreeze_fromhandler(struct lxc_handler *handler)
+static bool cgm_unfreeze(void *hdata)
 {
-	char *cgroup_path = handler->cgroup_info->data;
+	struct cgm_data *d = hdata;
 
-	if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", cgroup_path,
+	if (!d || !d->cgroup_path)
+		return false;
+
+	if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", d->cgroup_path,
 			"freezer.state", "THAWED") != 0) {
 		NihError *nerr;
 		nerr = nih_error_get();
 		ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
 		nih_free(nerr);
-		ERROR("Error unfreezing %s", cgroup_path);
+		ERROR("Error unfreezing %s", d->cgroup_path);
 		return false;
 	}
 	return true;
 }
 
-static bool setup_limits(struct lxc_handler *h, bool do_devices)
+static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
 {
+	struct cgm_data *d = hdata;
 	struct lxc_list *iterator;
 	struct lxc_cgroup *cg;
 	bool ret = false;
-	struct lxc_list *cgroup_settings = &h->conf->cgroup;
-	char *cgroup_path = h->cgroup_info->data;
 
 	if (lxc_list_empty(cgroup_settings))
 		return true;
 
+	if (!d || !d->cgroup_path)
+		return false;
+
 	lxc_list_for_each(iterator, cgroup_settings) {
 		char controller[100], *p;
 		cg = iterator->elem;
@@ -654,10 +723,10 @@ static bool setup_limits(struct lxc_handler *h, bool do_devices)
 		p = strchr(controller, '.');
 		if (p)
 			*p = '\0';
-		if (cgm_do_set(controller, cg->subsystem, cgroup_path
+		if (cgm_do_set(controller, cg->subsystem, d->cgroup_path
 				, cg->value) < 0) {
 			ERROR("Error setting %s to %s for %s\n",
-			      cg->subsystem, cg->value, h->name);
+			      cg->subsystem, cg->value, d->name);
 			goto out;
 		}
 
@@ -670,20 +739,17 @@ out:
 	return ret;
 }
 
-static bool cgm_setup_limits(struct lxc_handler *handler, bool with_devices)
-{
-	return setup_limits(handler, with_devices);
-}
-
-static bool cgm_chown(struct lxc_handler *handler)
+static bool cgm_chown(void *hdata, struct lxc_conf *conf)
 {
-	char *cgroup_path = handler->cgroup_info->data;
+	struct cgm_data *d = hdata;
 	int i;
 
+	if (!d || !d->cgroup_path)
+		return false;
 	for (i = 0; i < nr_subsystems; i++) {
-		if (!chown_cgroup(subsystems[i], cgroup_path, handler->conf))
+		if (!chown_cgroup(subsystems[i], d->cgroup_path, conf))
 			WARN("Failed to chown %s:%s to container root",
-				subsystems[i], cgroup_path);
+				subsystems[i], d->cgroup_path);
 	}
 	return true;
 }
@@ -771,8 +837,7 @@ static bool cgm_bind_dir(const char *root, const char *dirname)
  */
 #define CGMANAGER_LOWER_SOCK "/sys/fs/cgroup/cgmanager.lower"
 #define CGMANAGER_UPPER_SOCK "/sys/fs/cgroup/cgmanager"
-static bool cgm_mount_cgroup(const char *root,
-		struct lxc_cgroup_info *cgroup_info, int type)
+static bool cgm_mount_cgroup(void *hdata, const char *root, int type)
 {
 	if (dir_exists(CGMANAGER_LOWER_SOCK))
 		return cgm_bind_dir(root, CGMANAGER_LOWER_SOCK);
@@ -783,19 +848,20 @@ static bool cgm_mount_cgroup(const char *root,
 }
 
 static struct cgroup_ops cgmanager_ops = {
-	.destroy = cgm_destroy,
 	.init = cgm_init,
+	.destroy = cgm_destroy,
 	.create = cgm_create,
 	.enter = cgm_enter,
 	.create_legacy = NULL,
 	.get_cgroup = cgm_get_cgroup,
 	.get = cgm_get,
 	.set = cgm_set,
-	.unfreeze_fromhandler = cgm_unfreeze_fromhandler,
+	.unfreeze = cgm_unfreeze,
 	.setup_limits = cgm_setup_limits,
 	.name = "cgmanager",
 	.chown = cgm_chown,
 	.attach = cgm_attach,
 	.mount_cgroup = cgm_mount_cgroup,
+	.nrtasks = NULL,
 };
 #endif
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
new file mode 100644
index 0000000..b03f69d
--- /dev/null
+++ b/src/lxc/cgroup.c
@@ -0,0 +1,169 @@
+/*
+ * 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
+ */
+
+#include "cgroup.h"
+#include "conf.h"
+#include "log.h"
+#include "start.h"
+
+lxc_log_define(lxc_cgroup, lxc);
+
+static struct cgroup_ops *ops = NULL;
+
+extern struct cgroup_ops *cgfs_ops_init(void);
+extern struct cgroup_ops *cgm_ops_init(void);
+
+__attribute__((constructor))
+void cgroup_ops_init(void)
+{
+	if (ops) {
+		INFO("cgroup driver %s", ops->name);
+		return;
+	}
+
+	DEBUG("cgroup_init");
+	#if HAVE_CGMANAGER
+	ops = cgm_ops_init();
+	#endif
+	if (!ops)
+		ops = cgfs_ops_init();
+	if (ops)
+		INFO("Initialized cgroup driver %s", ops->name);
+}
+
+bool cgroup_init(struct lxc_handler *handler)
+{
+	if (handler->cgroup_data) {
+		ERROR("cgroup_init called on already inited handler");
+		return true;
+	}
+
+	if (ops) {
+		INFO("cgroup driver %s initing for %s", ops->name, handler->name);
+		handler->cgroup_data = ops->init(handler->name);
+	}
+	return handler->cgroup_data != NULL;
+}
+
+void cgroup_destroy(struct lxc_handler *handler)
+{
+	if (ops) {
+		ops->destroy(handler->cgroup_data);
+		handler->cgroup_data = NULL;
+	}
+}
+
+/* Create the container cgroups for all requested controllers */
+bool cgroup_create(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->create(handler->cgroup_data);
+	return false;
+}
+
+/*
+ * Enter the container init into its new cgroups for all
+ * requested controllers
+ */
+bool cgroup_enter(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->enter(handler->cgroup_data, handler->pid);
+	return false;
+}
+
+bool cgroup_create_legacy(struct lxc_handler *handler)
+{
+	if (ops && ops->create_legacy)
+		return ops->create_legacy(handler->cgroup_data, handler->pid);
+	return true;
+}
+
+const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+{
+	if (ops)
+		return ops->get_cgroup(handler->cgroup_data, subsystem);
+	return NULL;
+}
+
+bool cgroup_unfreeze(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->unfreeze(handler->cgroup_data);
+	return false;
+}
+
+bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
+{
+	if (ops)
+		return ops->setup_limits(handler->cgroup_data,
+					 &handler->conf->cgroup, with_devices);
+	return false;
+}
+
+bool cgroup_chown(struct lxc_handler *handler)
+{
+	if (ops && ops->chown)
+		return ops->chown(handler->cgroup_data, handler->conf);
+	return true;
+}
+
+bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
+{
+	if (ops) {
+		return ops->mount_cgroup(handler->cgroup_data, root, type);
+	}
+	return false;
+}
+
+int cgroup_nrtasks(struct lxc_handler *handler)
+{
+	if (ops) {
+		if (ops->nrtasks)
+			return ops->nrtasks(handler->cgroup_data);
+		else
+			WARN("CGROUP driver %s doesn't implement nrtasks", ops->name);
+	}
+	return -1;
+}
+
+bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
+{
+	if (ops)
+		return ops->attach(name, lxcpath, pid);
+	return false;
+}
+
+int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	if (ops)
+		return ops->set(filename, value, name, lxcpath);
+	return -1;
+}
+
+int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	if (ops)
+		return ops->get(filename, value, len, name, lxcpath);
+	return -1;
+}
diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
index da77473..6f9e5f6 100644
--- a/src/lxc/cgroup.h
+++ b/src/lxc/cgroup.h
@@ -20,195 +20,39 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
-#ifndef _ncgroup_h
-#define _ncgroup_h
-#include <stdbool.h>
-#include <stdint.h>
-#include <stddef.h>
-
-#include "state.h"
-
-struct cgroup_hierarchy;
-struct cgroup_meta_data;
-struct cgroup_mount_point;
-
-/*
- * cgroup_meta_data: the metadata about the cgroup infrastructure on this
- *                   host
- */
-struct cgroup_meta_data {
-	ptrdiff_t ref; /* simple refcount */
-	struct cgroup_hierarchy **hierarchies;
-	struct cgroup_mount_point **mount_points;
-	int maximum_hierarchy;
-};
-
-/*
- * cgroup_hierarchy: describes a single cgroup hierarchy
- *                   (may have multiple mount points)
- */
-struct cgroup_hierarchy {
-	int index;
-	bool used; /* false if the hierarchy should be ignored by lxc */
-	char **subsystems;
-	struct cgroup_mount_point *rw_absolute_mount_point;
-	struct cgroup_mount_point *ro_absolute_mount_point;
-	struct cgroup_mount_point **all_mount_points;
-	size_t all_mount_point_capacity;
-};
-
-/*
- * cgroup_mount_point: a mount point to where a hierarchy
- *                     is mounted to
- */
-struct cgroup_mount_point {
-	struct cgroup_hierarchy *hierarchy;
-	char *mount_point;
-	char *mount_prefix;
-	bool read_only;
-	bool need_cpuset_init;
-};
-
-/*
- * 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;
-	struct cgroup_meta_data *meta_ref;
-	struct cgroup_hierarchy *hierarchy;
-	char *cgroup_path;
-	char *cgroup_path_sub;
-	char **created_paths;
-	size_t created_paths_capacity;
-	size_t created_paths_count;
-	struct cgroup_mount_point *designated_mount_point;
-};
-
-/* meta data management:
- *    lxc_cgroup_load_meta  loads the meta data (using subsystem
- *                          whitelist from main lxc configuration)
- *    lxc_cgroup_load_meta2 does the same, but allows one to specify
- *                          a custom whitelist
- *    lxc_cgroup_get_meta   increments the refcount of a meta data
- *                          object
- *    lxc_cgroup_put_meta   decrements the refcount of a meta data
- *                          object, potentially destroying it
- */
-extern struct cgroup_meta_data *lxc_cgroup_load_meta();
-extern struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist);
-extern struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data);
-extern struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data);
-
-/* find the hierarchy corresponding to a given subsystem */
-extern struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem);
-
-/* find a mount point for a given hierarchy that has access to the cgroup in 'cgroup' and (if wanted) is writable */
-extern struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable);
-
-/* all-in-one: find a mount point for a given hierarchy that has access to the cgroup and return the correct path within */
-extern char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix);
 
-/* determine the cgroup membership of a given process */
-extern struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta);
-extern struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta);
-extern struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta);
+#ifndef __lxc_cgroup_h
+#define __lxc_cgroup_h
 
-/* 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);
-extern int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid);
-
-/* 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 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);
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/types.h>
 
 struct lxc_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);
-
-/*
- * lxc_cgroup_path_get: Get the absolute pathname for a cgroup
- * file for a running container.
- *
- * @filename  : the file of interest (e.g. "freezer.state") or
- *              the subsystem name (e.g. "freezer") in which case
- *              the directory where the cgroup may be modified
- *              will be returned
- * @name      : name of container to connect to
- * @lxcpath   : the lxcpath in which the container is running
- *
- * This is the exported function, which determines cgpath from the
- * lxc-start of the @name container running in @lxcpath.
- *
- * Returns path on success, NULL on error. The caller must free()
- * the returned path.
- */
-extern char *lxc_cgroup_path_get(const char *filename, const char *name,
-                                 const char *lxcpath);
-
+struct lxc_conf;
 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_cgroup_nrtasks_handler(struct lxc_handler *handler);
 
-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);
-
-/*
- * 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;
-};
-
-/* 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);
+	const char *name;
+
+	void *(*init)(const char *name);
+	void (*destroy)(void *hdata);
+	bool (*create)(void *hdata);
+	bool (*enter)(void *hdata, pid_t pid);
+	bool (*create_legacy)(void *hdata, pid_t pid);
+	const char *(*get_cgroup)(void *hdata, 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);
-	bool (*unfreeze_fromhandler)(struct lxc_handler *handler);
-	bool (*setup_limits)(struct lxc_handler *handler, bool with_devices);
-	bool (*chown)(struct lxc_handler *handler);
+	bool (*unfreeze)(void *hdata);
+	bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
+	bool (*chown)(void *hdata, struct lxc_conf *conf);
 	bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
-	bool (*mount_cgroup)(const char *root, struct lxc_cgroup_info *info,
-			int type);
-	const char *name;
-};
-
-struct cgfs_data {
-	struct cgroup_meta_data *meta;
-	struct cgroup_process_info *info;
+	bool (*mount_cgroup)(void *hdata, const char *root, int type);
+	int (*nrtasks)(void *hdata);
 };
 
-/*
- * backend-independent cgroup handlers
- */
+extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
+extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
 extern void cgroup_destroy(struct lxc_handler *handler);
 extern bool cgroup_init(struct lxc_handler *handler);
 extern bool cgroup_create(struct lxc_handler *handler);
@@ -217,11 +61,8 @@ extern bool cgroup_chown(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 bool lxc_cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
-extern bool lxc_setup_mount_cgroup(const char *root, struct lxc_cgroup_info *cgroup_info, int type);
-extern bool lxc_unfreeze_fromhandler(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);
+extern int cgroup_nrtasks(struct lxc_handler *handler);
+extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
+extern bool cgroup_unfreeze(struct lxc_handler *handler);
 
 #endif
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index e9ab42f..6b46c2c 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -430,7 +430,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
 				       struct lxc_handler *handler)
 {
 	struct lxc_cmd_rsp rsp;
-	char *path;
+	const char *path;
 
 	if (req->datalen < 1)
 		return -1;
@@ -439,7 +439,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
 	if (!path)
 		return -1;
 	rsp.datalen = strlen(path) + 1,
-	rsp.data = path;
+	rsp.data = (char *)path;
 	rsp.ret = 0;
 
 	return lxc_cmd_rsp_send(fd, &rsp);
@@ -590,7 +590,12 @@ 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) {
-		if (lxc_unfreeze_fromhandler(handler))
+		/* we can't just use lxc_unfreeze() since we are already in the
+		 * context of handling the STOP cmd in lxc-start, and calling
+		 * lxc_unfreeze() would do another cmd (GET_CGROUP) which would
+		 * deadlock us
+		 */
+		if (cgroup_unfreeze(handler))
 			return 0;
 		ERROR("Failed to unfreeze %s:%s", handler->lxcpath, handler->name);
 		rsp.ret = -1;
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index fed5327..3a03db8 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -63,7 +63,6 @@
 #include "utils.h"
 #include "conf.h"
 #include "log.h"
-#include "lxc.h"	/* for lxc_cgroup_set() */
 #include "caps.h"       /* for lxc_caps_last_cap() */
 #include "bdev.h"
 #include "cgroup.h"
@@ -670,7 +669,7 @@ int pin_rootfs(const char *rootfs)
 	return fd;
 }
 
-static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cgroup_info *cgroup_info)
+static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_handler *handler)
 {
 	int r;
 	size_t i;
@@ -744,8 +743,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cg
 	}
 
 	if (flags & LXC_AUTO_CGROUP_MASK) {
-		if (!lxc_setup_mount_cgroup(conf->rootfs.mount, cgroup_info,
-					flags & LXC_AUTO_CGROUP_MASK)) {
+		if (!cgroup_mount(conf->rootfs.mount, handler,
+				  flags & LXC_AUTO_CGROUP_MASK)) {
 			SYSERROR("error mounting /sys/fs/cgroup");
 			return -1;
 		}
@@ -3497,7 +3496,6 @@ int lxc_setup(struct lxc_handler *handler)
 	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)) {
@@ -3535,7 +3533,7 @@ int lxc_setup(struct lxc_handler *handler)
 	/* do automatic mounts (mainly /proc and /sys), but exclude
 	 * those that need to wait until other stuff has finished
 	 */
-	if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & ~LXC_AUTO_CGROUP_MASK, cgroup_info) < 0) {
+	if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & ~LXC_AUTO_CGROUP_MASK, handler) < 0) {
 		ERROR("failed to setup the automatic mounts for '%s'", name);
 		return -1;
 	}
@@ -3554,7 +3552,7 @@ int lxc_setup(struct lxc_handler *handler)
 	 * before, /sys could not have been mounted
 	 * (is either mounted automatically or via fstab entries)
 	 */
-	if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, cgroup_info) < 0) {
+	if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, handler) < 0) {
 		ERROR("failed to setup the automatic mounts for '%s'", name);
 		return -1;
 	}
diff --git a/src/lxc/freezer.c b/src/lxc/freezer.c
index 89c7fab..c79f139 100644
--- a/src/lxc/freezer.c
+++ b/src/lxc/freezer.c
@@ -35,18 +35,53 @@
 #include "state.h"
 #include "monitor.h"
 #include "log.h"
-#include "cgroup.h"
+#include "lxc.h"
 
 lxc_log_define(lxc_freezer, lxc);
 
+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)
+		return -1;
+
+	if (v[strlen(v)-1] == '\n')
+		v[strlen(v)-1] = '\0';
+	return lxc_str2state(v);
+}
+
+static int do_freeze_thaw(int freeze, const char *name, const char *lxcpath)
+{
+	char v[100];
+	const char *state = freeze ? "FROZEN" : "THAWED";
+
+	if (lxc_cgroup_set("freezer.state", state, name, lxcpath) < 0) {
+		ERROR("Failed to freeze %s:%s", lxcpath, name);
+		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);
+	}
+}
 
 int lxc_freeze(const char *name, const char *lxcpath)
 {
 	lxc_monitor_send_state(name, FREEZING, lxcpath);
-	return freeze_unfreeze(name, 1, lxcpath);
+	return do_freeze_thaw(1, name, lxcpath);
 }
 
 int lxc_unfreeze(const char *name, const char *lxcpath)
 {
-	return freeze_unfreeze(name, 0, lxcpath);
+	return do_freeze_thaw(0, name, lxcpath);
 }
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index 56f9fe2..8775640 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
@@ -129,17 +129,6 @@ extern int lxc_unfreeze(const char *name, const char *lxcpath);
  */
 extern lxc_state_t lxc_state(const char *name, const char *lxcpath);
 
-struct lxc_handler;
-/*
- * Set a specified value for a specified subsystem. The specified
- * subsystem must be fully specified, eg. "cpu.shares"
- * @filename  : the cgroup attribute filename
- * @value     : the value to be set
- * @handler   : the lxc_handler structure of the container
- * Returns 0 on success, < 0 otherwise
- */
-extern int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler);
-
 /*
  * Set a specified value for a specified subsystem. The specified
  * subsystem must be fully specified, eg. "cpu.shares"
diff --git a/src/lxc/lxcutmp.c b/src/lxc/lxcutmp.c
index 15dd71c..24cfa75 100644
--- a/src/lxc/lxcutmp.c
+++ b/src/lxc/lxcutmp.c
@@ -291,7 +291,7 @@ static int utmp_get_ntasks(struct lxc_handler *handler)
 {
 	int ntasks;
 
-	ntasks = lxc_cgroup_nrtasks_handler(handler);
+	ntasks = cgroup_nrtasks(handler);
 
 	if (ntasks < 0) {
 		ERROR("failed to get the number of tasks");
diff --git a/src/lxc/start.h b/src/lxc/start.h
index c30c661..63fa8b4 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 lxc_cgroup_info *cgroup_info;
+	void *cgroup_data;
 };
 
 extern struct lxc_handler *lxc_init(const char *name, struct lxc_conf *, const char *);
diff --git a/src/lxc/state.c b/src/lxc/state.c
index 81648e0..db833b0 100644
--- a/src/lxc/state.c
+++ b/src/lxc/state.c
@@ -69,6 +69,8 @@ lxc_state_t lxc_str2state(const char *state)
 
 lxc_state_t lxc_getstate(const char *name, const char *lxcpath)
 {
+	extern lxc_state_t freezer_state(const char *name, const char *lxcpath);
+
 	lxc_state_t state = freezer_state(name, lxcpath);
 	if (state != FROZEN && state != FREEZING)
 		state = lxc_cmd_get_state(name, lxcpath);
diff --git a/src/tests/cgpath.c b/src/tests/cgpath.c
index f0e2de8..c8a09e8 100644
--- a/src/tests/cgpath.c
+++ b/src/tests/cgpath.c
@@ -50,9 +50,7 @@ static int test_running_container(const char *lxcpath,
 	int ret = -1;
 	struct lxc_container *c = NULL;
 	char *cgrelpath;
-	char *cgabspath;
 	char  relpath[PATH_MAX+1];
-	char  abspath[PATH_MAX+1];
 	char  value[NAME_MAX], value_save[NAME_MAX];
 
 	sprintf(relpath, "%s/%s", group ? group : "lxc", name);
@@ -109,32 +107,8 @@ static int test_running_container(const char *lxcpath,
 		goto err3;
 	}
 
-	cgabspath = lxc_cgroup_path_get("freezer", c->name, c->config_path);
-	if (!cgabspath) {
-		TSTERR("lxc_cgroup_path_get returned NULL");
-		goto err3;
-	}
-	sprintf(abspath, "%s/%s/%s", "freezer", group ? group : "lxc", c->name);
-	if (!strstr(cgabspath, abspath)) {
-		TSTERR("lxc_cgroup_path_get %s not in %s", abspath, cgabspath);
-		goto err4;
-	}
-
-	free(cgabspath);
-	cgabspath = lxc_cgroup_path_get("freezer.state", c->name, c->config_path);
-	if (!cgabspath) {
-		TSTERR("lxc_cgroup_path_get returned NULL");
-		goto err3;
-	}
-	sprintf(abspath, "%s/%s/%s", "freezer", group ? group : "lxc", c->name);
-	if (!strstr(cgabspath, abspath)) {
-		TSTERR("lxc_cgroup_path_get %s not in %s", abspath, cgabspath);
-		goto err4;
-	}
-
 	ret = 0;
-err4:
-	free(cgabspath);
+
 err3:
 	free(cgrelpath);
 err2:
-- 
1.8.5.3



More information about the lxc-devel mailing list