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

Serge Hallyn serge.hallyn at ubuntu.com
Thu Feb 6 04:51:53 UTC 2014


Quoting Dwight Engen (dwight.engen at oracle.com):
> - 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

Hi Dwight,

boy this diff got into some unfortunate strides (with near-identical
code being removed then inserted pages later) making it harder
to read than necessary :)

> Signed-off-by: Dwight Engen <dwight.engen at oracle.com>

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

(I'll apply after I run some tests)

> ---
>  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
> 
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel


More information about the lxc-devel mailing list