[lxc-devel] [PATCH RFC] cgroups: use cgfs when possible
Serge Hallyn
serge.hallyn at ubuntu.com
Sun May 17 20:15:48 UTC 2015
Because it is easier on the host. When creating many containers,
reducing the load on the cgroup manager can greatly reduce the
cpu usage. Until now, we have used cgmanager whenever we could.
Now we use cgfs when we can, and switch to cgmanager if needed.
At cgroup init, we first check whether we can use cgfs. If we
can, we use it rather than cgmanager. This means that cgfs needs
to actually check whether it can be used. We do this by making
sure that every needed hierarchy has a writeable mountpoint.
We also now need to have cgfs call cgmanager's mount_setup(), as
any nested use of cgroups may well need to be using cgmanager.
This requires a patch to the lxcfs mount hook to avoid failure
on mkdir. (A better fix would be nice, but this suffices to make
things work)
This also gets rid of the cgroup_driver enum, which wasn't
actually used anywhere.
Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
src/lxc/cgfs.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
src/lxc/cgmanager.c | 3 +--
src/lxc/cgroup.c | 12 ++++--------
src/lxc/cgroup.h | 10 +++-------
4 files changed, 49 insertions(+), 22 deletions(-)
diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c
index fcb3cde..fe7b06d 100644
--- a/src/lxc/cgfs.c
+++ b/src/lxc/cgfs.c
@@ -1338,12 +1338,16 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
struct cgfs_data *cgfs_d;
struct cgroup_process_info *info, *base_info;
int r, saved_errno = 0;
+ bool cgm_setup;
cgfs_d = hdata;
if (!cgfs_d)
return false;
base_info = cgfs_d->info;
+ /* Try to set up cgmanager mounts; ignore failure */
+ cgm_setup = cgm_mount_cgroup(hdata, root, type);
+
/* If we get passed the _NOSPEC types, we default to _MIXED, since we don't
* have access to the lxc_conf object at this point. It really should be up
* to the caller to fix this, but this doesn't really hurt.
@@ -1363,10 +1367,16 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
if (!path)
return false;
snprintf(path, bufsz, "%s/sys/fs/cgroup", root);
- r = mount("cgroup_root", path, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "size=10240k,mode=755");
- if (r < 0) {
- SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container");
- return false;
+
+ if (!cgm_setup) {
+ r = mount("cgroup_root", path, "tmpfs",
+ MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
+ "size=10240k,mode=755");
+ if (r < 0) {
+ SYSERROR("could not mount tmpfs to /sys/fs/cgroup in"
+ "the container");
+ return false;
+ }
}
/* now mount all the hierarchies we care about */
@@ -2217,8 +2227,35 @@ static bool init_cpuset_if_needed(struct cgroup_mount_point *mp,
do_init_cpuset_file(mp, path, "/cpuset.mems") );
}
+static bool verify_cgops_usable(void)
+{
+ struct cgroup_meta_data *meta;
+ bool ret = false;
+ int i;
+
+ meta = lxc_cgroup_load_meta();
+ if (!meta)
+ return false;
+ /* verify that all paths are writeable */
+ for (i = 0; i <= meta->maximum_hierarchy; i++) {
+ struct cgroup_hierarchy *h = meta->hierarchies[i];
+ if (!h || !h->used)
+ continue;
+ if (!h->rw_absolute_mount_point) {
+ INFO("unwriteable cgroup mountpoint, cannot use cgfs");
+ goto out;
+ }
+ }
+ ret = true;
+out:
+ lxc_cgroup_put_meta(meta);
+ return ret;
+}
+
struct cgroup_ops *cgfs_ops_init(void)
{
+ if (!verify_cgops_usable())
+ return NULL;
return &cgfs_ops;
}
@@ -2413,5 +2450,4 @@ static struct cgroup_ops cgfs_ops = {
.chown = NULL,
.mount_cgroup = cgroupfs_mount_cgroup,
.nrtasks = cgfs_nrtasks,
- .driver = CGFS,
};
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
index 7dddb89..379d11c 100644
--- a/src/lxc/cgmanager.c
+++ b/src/lxc/cgmanager.c
@@ -1383,7 +1383,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(void *hdata, const char *root, int type)
+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);
@@ -1411,6 +1411,5 @@ static struct cgroup_ops cgmanager_ops = {
.mount_cgroup = cgm_mount_cgroup,
.nrtasks = cgm_get_nrtasks,
.disconnect = NULL,
- .driver = CGMANAGER,
};
#endif
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index 2362ad8..5498028 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -45,13 +45,14 @@ void cgroup_ops_init(void)
}
DEBUG("cgroup_init");
+ ops = cgfs_ops_init();
#if HAVE_CGMANAGER
- ops = cgm_ops_init();
- #endif
if (!ops)
- ops = cgfs_ops_init();
+ ops = cgm_ops_init();
+ #endif
if (ops)
INFO("Initialized cgroup driver %s", ops->name);
+ ERROR("Failed initializing cgroup driver!");
}
bool cgroup_init(struct lxc_handler *handler)
@@ -189,8 +190,3 @@ void cgroup_disconnect(void)
if (ops && ops->disconnect)
ops->disconnect();
}
-
-cgroup_driver_t cgroup_driver(void)
-{
- return ops->driver;
-}
diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
index 6706939..46d9977 100644
--- a/src/lxc/cgroup.h
+++ b/src/lxc/cgroup.h
@@ -32,11 +32,6 @@ struct lxc_handler;
struct lxc_conf;
struct lxc_list;
-typedef enum {
- CGFS,
- CGMANAGER,
-} cgroup_driver_t;
-
struct cgroup_ops {
const char *name;
@@ -56,7 +51,6 @@ struct cgroup_ops {
bool (*mount_cgroup)(void *hdata, const char *root, int type);
int (*nrtasks)(void *hdata);
void (*disconnect)(void);
- cgroup_driver_t driver;
};
extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
@@ -78,6 +72,8 @@ extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *su
extern const char *cgroup_canonical_path(struct lxc_handler *handler);
extern bool cgroup_unfreeze(struct lxc_handler *handler);
extern void cgroup_disconnect(void);
-extern cgroup_driver_t cgroup_driver(void);
+
+/* cgfs uses this from cgmanager */
+bool cgm_mount_cgroup(void *hdata, const char *root, int type);
#endif
--
2.1.4
More information about the lxc-devel
mailing list