#include "include/strlcat.h"
#endif
-#define __cgfsng_ops__
-
lxc_log_define(cgfsng, cgroup);
static void free_string_list(char **clist)
len = strlen(entry);
prefixed = must_alloc(len + 6);
- memcpy(prefixed, "name=", sizeof("name=") - 1);
- memcpy(prefixed + sizeof("name=") - 1, entry, len);
+
+ memcpy(prefixed, "name=", STRLITERALLEN("name="));
+ memcpy(prefixed + STRLITERALLEN("name="), entry, len);
prefixed[len + 5] = '\0';
return prefixed;
}
/* Given a handler's cgroup data, return the struct hierarchy for the controller
* @c, or NULL if there is none.
*/
-struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *c)
+struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *controller)
{
int i;
- if (!ops->hierarchies)
+ errno = ENOENT;
+
+ if (!ops->hierarchies) {
+ TRACE("There are no useable cgroup controllers");
return NULL;
+ }
for (i = 0; ops->hierarchies[i]; i++) {
- if (!c) {
+ if (!controller) {
/* This is the empty unified hierarchy. */
if (ops->hierarchies[i]->controllers &&
!ops->hierarchies[i]->controllers[0])
continue;
}
- if (string_in_list(ops->hierarchies[i]->controllers, c))
+ if (string_in_list(ops->hierarchies[i]->controllers, controller))
return ops->hierarchies[i];
}
+ if (controller)
+ WARN("There is no useable %s controller", controller);
+ else
+ WARN("There is no empty unified cgroup hierarchy");
+
return NULL;
}
}
}
- clonechildrenpath =
- must_make_path(cgpath, "cgroup.clone_children", NULL);
+ clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
/* unified hierarchy doesn't have clone_children */
if (!file_exists(clonechildrenpath)) {
free(clonechildrenpath);
return cgroup_rmdir(arg->hierarchies, arg->container_cgroup);
}
-__cgfsng_ops__ static void cgfsng_destroy(struct cgroup_ops *ops, struct lxc_handler *handler)
+__cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
+ struct lxc_handler *handler)
{
int ret;
struct generic_userns_exec_data wrap;
}
}
+__cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
+ struct lxc_handler *handler)
+{
+ int len;
+ char *pivot_path;
+ struct lxc_conf *conf = handler->conf;
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
+
+ if (!ops->hierarchies)
+ return;
+
+ len = snprintf(pidstr, sizeof(pidstr), "%d", handler->monitor_pid);
+ if (len < 0 || (size_t)len >= sizeof(pidstr))
+ return;
+
+ for (int i = 0; ops->hierarchies[i]; i++) {
+ int ret;
+ struct hierarchy *h = ops->hierarchies[i];
+
+ if (!h->monitor_full_path)
+ continue;
+
+ if (conf && conf->cgroup_meta.dir)
+ pivot_path = must_make_path(h->mountpoint,
+ h->container_base_path,
+ conf->cgroup_meta.dir,
+ PIVOT_CGROUP,
+ "cgroup.procs", NULL);
+ else
+ pivot_path = must_make_path(h->mountpoint,
+ h->container_base_path,
+ PIVOT_CGROUP,
+ "cgroup.procs", NULL);
+
+ ret = mkdir_p(pivot_path, 0755);
+ if (ret < 0 && errno != EEXIST)
+ goto next;
+
+ /* Move ourselves into the pivot cgroup to delete our own
+ * cgroup.
+ */
+ ret = lxc_write_to_file(pivot_path, pidstr, len, false, 0666);
+ if (ret != 0)
+ goto next;
+
+ ret = recursive_destroy(h->monitor_full_path);
+ if (ret < 0)
+ WARN("Failed to destroy \"%s\"", h->monitor_full_path);
+
+ next:
+ free(pivot_path);
+ }
+}
+
static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
{
size_t i, parts_len;
if (dir_exists(h->monitor_full_path))
return true;
+ if (!cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
+ ERROR("Failed to handle legacy cpuset controller");
+ return false;
+ }
+
ret = mkdir_p(h->monitor_full_path, 0755);
if (ret < 0) {
ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path);
h->container_full_path = NULL;
}
-__cgfsng_ops__ static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
+__cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
struct lxc_handler *handler)
{
- char *monitor_cgroup;
+ char *monitor_cgroup, *offset, *tmp;
+ int idx = 0;
+ size_t len;
bool bret = false;
struct lxc_conf *conf = handler->conf;
return bret;
if (conf->cgroup_meta.dir)
- monitor_cgroup = lxc_string_join("/", (const char *[]){conf->cgroup_meta.dir, ops->monitor_pattern, handler->name, NULL}, false);
+ tmp = lxc_string_join("/",
+ (const char *[]){conf->cgroup_meta.dir,
+ ops->monitor_pattern,
+ handler->name, NULL},
+ false);
else
- monitor_cgroup = must_make_path(ops->monitor_pattern, handler->name, NULL);
- if (!monitor_cgroup)
+ tmp = must_make_path(ops->monitor_pattern, handler->name, NULL);
+ if (!tmp)
return bret;
- for (int i = 0; ops->hierarchies[i]; i++) {
- if (!monitor_create_path_for_hierarchy(ops->hierarchies[i], monitor_cgroup)) {
- ERROR("Failed to create cgroup \"%s\"", ops->hierarchies[i]->monitor_full_path);
- free(ops->hierarchies[i]->container_full_path);
- ops->hierarchies[i]->container_full_path = NULL;
- for (int j = 0; j < i; j++)
- remove_path_for_hierarchy(ops->hierarchies[j], monitor_cgroup, true);
- goto on_error;
+ len = strlen(tmp) + 5; /* leave room for -NNN\0 */
+ monitor_cgroup = must_alloc(len);
+ (void)strlcpy(monitor_cgroup, tmp, len);
+ free(tmp);
+ offset = monitor_cgroup + len - 5;
+
+ do {
+ if (idx) {
+ int ret = snprintf(offset, 5, "-%d", idx);
+ if (ret < 0 || (size_t)ret >= 5)
+ goto on_error;
}
- }
- bret = true;
+ for (int i = 0; ops->hierarchies[i]; i++) {
+ if (!monitor_create_path_for_hierarchy(ops->hierarchies[i], monitor_cgroup)) {
+ ERROR("Failed to create cgroup \"%s\"", ops->hierarchies[i]->monitor_full_path);
+ free(ops->hierarchies[i]->container_full_path);
+ ops->hierarchies[i]->container_full_path = NULL;
+
+ for (int j = 0; j < i; j++)
+ remove_path_for_hierarchy(ops->hierarchies[j], monitor_cgroup, true);
+
+ idx++;
+ break;
+ }
+ }
+ } while (idx > 0 && idx < 1000);
+
+ if (idx < 1000)
+ bret = true;
on_error:
free(monitor_cgroup);
/* Try to create the same cgroup in all hierarchies. Start with cgroup_pattern;
* next cgroup_pattern-1, -2, ..., -999.
*/
-__cgfsng_ops__ static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
+__cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
struct lxc_handler *handler)
{
int i;
return false;
}
-__cgfsng_ops__ static bool __do_cgroup_enter(struct cgroup_ops *ops, pid_t pid,
+__cgfsng_ops static bool __do_cgroup_enter(struct cgroup_ops *ops, pid_t pid,
bool monitor)
{
int len;
- char pidstr[25];
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
- len = snprintf(pidstr, 25, "%d", pid);
- if (len < 0 || len >= 25)
+ len = snprintf(pidstr, sizeof(pidstr), "%d", pid);
+ if (len < 0 || (size_t)len >= sizeof(pidstr))
return false;
for (int i = 0; ops->hierarchies[i]; i++) {
return true;
}
-__cgfsng_ops__ static bool cgfsng_monitor_enter(struct cgroup_ops *ops, pid_t pid)
+__cgfsng_ops static bool cgfsng_monitor_enter(struct cgroup_ops *ops, pid_t pid)
{
return __do_cgroup_enter(ops, pid, true);
}
return 0;
}
-__cgfsng_ops__ static bool cgfsng_chown(struct cgroup_ops *ops,
+__cgfsng_ops static bool cgfsng_chown(struct cgroup_ops *ops,
struct lxc_conf *conf)
{
struct generic_userns_exec_data wrap;
return __cg_mount_direct(type, h, controllerpath);
}
-__cgfsng_ops__ static bool cgfsng_mount(struct cgroup_ops *ops,
+__cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
struct lxc_handler *handler,
const char *root, int type)
{
return count;
}
-__cgfsng_ops__ static int cgfsng_nrtasks(struct cgroup_ops *ops)
+__cgfsng_ops static int cgfsng_nrtasks(struct cgroup_ops *ops)
{
int count;
char *path;
}
/* Only root needs to escape to the cgroup of its init. */
-__cgfsng_ops__ static bool cgfsng_escape(const struct cgroup_ops *ops,
+__cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops,
struct lxc_conf *conf)
{
int i;
return true;
}
-__cgfsng_ops__ static int cgfsng_num_hierarchies(struct cgroup_ops *ops)
+__cgfsng_ops static int cgfsng_num_hierarchies(struct cgroup_ops *ops)
{
int i;
return i;
}
-__cgfsng_ops__ static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, char ***out)
+__cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, char ***out)
{
int i;
/* TODO: If the unified cgroup hierarchy grows a freezer controller this needs
* to be adapted.
*/
-__cgfsng_ops__ static bool cgfsng_unfreeze(struct cgroup_ops *ops)
+__cgfsng_ops static bool cgfsng_unfreeze(struct cgroup_ops *ops)
{
int ret;
char *fullpath;
return true;
}
-__cgfsng_ops__ static const char *cgfsng_get_cgroup(struct cgroup_ops *ops,
+__cgfsng_ops static const char *cgfsng_get_cgroup(struct cgroup_ops *ops,
const char *controller)
{
struct hierarchy *h;
free(full_path);
- len = strlen(base_path) + sizeof("/lxc-1000") - 1 +
- sizeof("/cgroup-procs") - 1;
+ len = strlen(base_path) + STRLITERALLEN("/lxc-1000") +
+ STRLITERALLEN("/cgroup-procs");
full_path = must_alloc(len + 1);
do {
if (idx)
return fret;
}
-__cgfsng_ops__ static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
+__cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
const char *lxcpath, pid_t pid)
{
int i, len, ret;
- char pidstr[25];
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
- len = snprintf(pidstr, 25, "%d", pid);
- if (len < 0 || len >= 25)
+ len = snprintf(pidstr, sizeof(pidstr), "%d", pid);
+ if (len < 0 || (size_t)len >= sizeof(pidstr))
return false;
for (i = 0; ops->hierarchies[i]; i++) {
* don't have a cgroup_data set up, so we ask the running container through the
* commands API for the cgroup path.
*/
-__cgfsng_ops__ static int cgfsng_get(struct cgroup_ops *ops, const char *filename,
+__cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename,
char *value, size_t len, const char *name,
const char *lxcpath)
{
* don't have a cgroup_data set up, so we ask the running container through the
* commands API for the cgroup path.
*/
-__cgfsng_ops__ static int cgfsng_set(struct cgroup_ops *ops,
+__cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
const char *filename, const char *value,
const char *name, const char *lxcpath)
{
return true;
}
-__cgfsng_ops__ static bool cgfsng_setup_limits(struct cgroup_ops *ops,
+__cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops,
struct lxc_conf *conf,
bool do_devices)
{
return cg_hybrid_init(ops, relative);
}
-__cgfsng_ops__ static bool cgfsng_data_init(struct cgroup_ops *ops)
+__cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops)
{
const char *cgroup_pattern;
return false;
}
ops->cgroup_pattern = must_copy_string(cgroup_pattern);
- ops->monitor_pattern = must_copy_string("lxc.monitor");
+ ops->monitor_pattern = MONITOR_CGROUP;
return true;
}
}
cgfsng_ops->data_init = cgfsng_data_init;
- cgfsng_ops->destroy = cgfsng_destroy;
+ cgfsng_ops->payload_destroy = cgfsng_payload_destroy;
+ cgfsng_ops->monitor_destroy = cgfsng_monitor_destroy;
cgfsng_ops->monitor_create = cgfsng_monitor_create;
cgfsng_ops->monitor_enter = cgfsng_monitor_enter;
cgfsng_ops->payload_create = cgfsng_payload_create;