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

Stéphane Graber stgraber at ubuntu.com
Wed Jan 15 15:43:40 UTC 2014


On Tue, Jan 14, 2014 at 04:41:36PM -0600, Serge Hallyn wrote:
> This patch splits out most of the cgroupfs-specific code, so that
> cgroup-manager versions can be plugged in.  The case I did
> not handle is cgroup_enter at lxc_attach.  I'm hoping that case can
> be greatly simplified, but will worry about it after fleshing out the
> cgroup manager handlers.
> 
> This also simplify the freezer functions.
> 
> This seems to not regress my common tests when running without
> cgmanager, but I'd like to do a bit more testing before pushing.
> However I was hoping to get some more eyes on this so am sending it
> out now.
> 
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>

So I haven't spotted anything obviously wrong with it, besides the few
functions that are currently marked as unimplemented.

I also confirmed that the code still builds on all supported platforms
(without cgmanager), so if it breaks the existing code path, it doesn't
do so in any obvious way.

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

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140115/0455d09c/attachment.pgp>


More information about the lxc-devel mailing list