]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/cgroups/cgfsng.c
cgfs: remove redundancy utils
[mirror_lxc.git] / src / lxc / cgroups / cgfsng.c
index 0f3296919ac7f5084dabfe9ea32d4039342ad135..1631319ec8abdfccb1fed72fe9842f966526b16a 100644 (file)
  *
  * This new implementation assumes that cgroup filesystems are mounted
  * under /sys/fs/cgroup/clist where clist is either the controller, or
- * a comman-separated list of controllers.
+ * a comma-separated list of controllers.
  */
 
-#include "config.h"
-
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <grp.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include "caps.h"
 #include "cgroup.h"
 #include "cgroup_utils.h"
 #include "commands.h"
 #include "conf.h"
+#include "config.h"
 #include "log.h"
 #include "macro.h"
 #include "storage/storage.h"
@@ -67,8 +69,6 @@
 #include "include/strlcat.h"
 #endif
 
-#define __cgfsng_ops__
-
 lxc_log_define(cgfsng, cgroup);
 
 static void free_string_list(char **clist)
@@ -84,12 +84,6 @@ static void free_string_list(char **clist)
        free(clist);
 }
 
-/* Allocate a pointer, do not fail. */
-static void *must_alloc(size_t sz)
-{
-       return must_realloc(NULL, sz);
-}
-
 /* Given a pointer to a null-terminated array of pointers, realloc to add one
  * entry, and point the new entry to NULL. Do not fail. Return the index to the
  * second-to-last entry - that is, the one which is now available for use
@@ -134,11 +128,12 @@ static char *cg_legacy_must_prefix_named(char *entry)
        char *prefixed;
 
        len = strlen(entry);
-       prefixed = must_alloc(len + 6);
+       prefixed = must_realloc(NULL, 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;
 }
 
@@ -180,15 +175,19 @@ static void must_append_controller(char **klist, char **nlist, char ***clist,
 /* 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])
@@ -197,10 +196,15 @@ struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *c)
                        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;
 }
 
@@ -531,7 +535,7 @@ static bool copy_parent_file(char *path, char *file)
        if (len <= 0)
                goto on_error;
 
-       value = must_alloc(len + 1);
+       value = must_realloc(NULL, len + 1);
        ret = lxc_read_from_file(fpath, value, len);
        if (ret != len)
                goto on_error;
@@ -586,8 +590,7 @@ static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
                }
        }
 
-       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);
@@ -815,7 +818,7 @@ static struct hierarchy *add_hierarchy(struct hierarchy ***h, char **clist, char
        struct hierarchy *new;
        int newentry;
 
-       new = must_alloc(sizeof(*new));
+       new = must_realloc(NULL, sizeof(*new));
        new->controllers = clist;
        new->mountpoint = mountpoint;
        new->container_base_path = container_base_path;
@@ -854,7 +857,7 @@ static char *cg_hybrid_get_mountpoint(char *line)
        *p2 = '\0';
 
        len = strlen(p);
-       sret = must_alloc(len + 1);
+       sret = must_realloc(NULL, len + 1);
        memcpy(sret, p, len);
        sret[len] = '\0';
        return sret;
@@ -870,7 +873,7 @@ static char *copy_to_eol(char *p)
                return NULL;
 
        len = p2 - p;
-       sret = must_alloc(len + 1);
+       sret = must_realloc(NULL, len + 1);
        memcpy(sret, p, len);
        sret[len] = '\0';
        return sret;
@@ -1104,7 +1107,8 @@ static int cgroup_rmdir_wrapper(void *data)
        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;
@@ -1125,6 +1129,82 @@ __cgfsng_ops__ static void cgfsng_destroy(struct cgroup_ops *ops, struct lxc_han
        }
 }
 
+__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;
+               char *chop;
+               char pivot_cgroup[] = PIVOT_CGROUP;
+               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);
+
+               chop = strrchr(pivot_path, '/');
+               if (chop)
+                       *chop = '\0';
+
+               /*
+                * Make sure not to pass in the ro string literal PIVOT_CGROUP
+                * here.
+                */
+               if (!cg_legacy_handle_cpuset_hierarchy(h, pivot_cgroup)) {
+                       WARN("Failed to handle legacy cpuset controller");
+                       goto next;
+               }
+
+               ret = mkdir_p(pivot_path, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSWARN("Failed to create cgroup \"%s\"\n", pivot_path);
+                       goto next;
+               }
+
+               if (chop)
+                       *chop = '/';
+
+               /* 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) {
+                       SYSWARN("Failed to move monitor %s to \"%s\"\n", pidstr, pivot_path);
+                       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;
@@ -1193,15 +1273,53 @@ on_error:
        return bret;
 }
 
+static int mkdir_eexist_on_last(const char *dir, mode_t mode)
+{
+       const char *tmp = dir;
+       const char *orig = dir;
+       size_t orig_len;
+
+       orig_len = strlen(dir);
+       do {
+               int ret;
+               size_t cur_len;
+               char *makeme;
+
+               dir = tmp + strspn(tmp, "/");
+               tmp = dir + strcspn(dir, "/");
+
+               errno = ENOMEM;
+               cur_len = dir - orig;
+               makeme = strndup(orig, cur_len);
+               if (!makeme)
+                       return -1;
+
+               ret = mkdir(makeme, mode);
+               if (ret < 0) {
+                       if ((errno != EEXIST) || (orig_len == cur_len)) {
+                               SYSERROR("Failed to create directory \"%s\"", makeme);
+                               free(makeme);
+                               return -1;
+                       }
+               }
+               free(makeme);
+
+       } while (tmp != dir);
+
+       return 0;
+}
+
 static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname)
 {
        int ret;
 
-       h->monitor_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
-       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);
+       h->monitor_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
+       ret = mkdir_eexist_on_last(h->monitor_full_path, 0755);
        if (ret < 0) {
                ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path);
                return false;
@@ -1214,18 +1332,13 @@ static bool container_create_path_for_hierarchy(struct hierarchy *h, char *cgnam
 {
        int ret;
 
-       h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
-       if (dir_exists(h->container_full_path)) {
-               ERROR("The cgroup \"%s\" already existed", h->container_full_path);
-               return false;
-       }
-
        if (!cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
                ERROR("Failed to handle legacy cpuset controller");
                return false;
        }
 
-       ret = mkdir_p(h->container_full_path, 0755);
+       h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
+       ret = mkdir_eexist_on_last(h->container_full_path, 0755);
        if (ret < 0) {
                ERROR("Failed to create cgroup \"%s\"", h->container_full_path);
                return false;
@@ -1256,10 +1369,12 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname, bool mo
                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 i, idx = 0;
+       size_t len;
        bool bret = false;
        struct lxc_conf *conf = handler->conf;
 
@@ -1267,24 +1382,47 @@ __cgfsng_ops__ static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
                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_realloc(tmp, len);
+       offset = monitor_cgroup + len - 5;
+       *offset = 0;
+
+       do {
+               if (idx) {
+                       int ret = snprintf(offset, 5, "-%d", idx);
+                       if (ret < 0 || (size_t)ret >= 5)
+                               goto on_error;
                }
-       }
 
-       bret = true;
+               for (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 (ops->hierarchies[i] && idx > 0 && idx < 1000);
+
+       if (idx < 1000) {
+               bret = true;
+               INFO("The monitor process uses \"%s\" as cgroup", monitor_cgroup);
+       }
 
 on_error:
        free(monitor_cgroup);
@@ -1295,7 +1433,7 @@ on_error:
 /* 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;
@@ -1322,7 +1460,7 @@ __cgfsng_ops__ static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
        }
 
        len = strlen(tmp) + 5; /* leave room for -NNN\0 */
-       container_cgroup = must_alloc(len);
+       container_cgroup = must_realloc(NULL, len);
        (void)strlcpy(container_cgroup, tmp, len);
        free(tmp);
        offset = container_cgroup + len - 5;
@@ -1361,6 +1499,7 @@ again:
        }
 
        ops->container_cgroup = container_cgroup;
+       INFO("The container uses \"%s\" as cgroup", container_cgroup);
 
        return true;
 
@@ -1370,14 +1509,14 @@ out_free:
        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++) {
@@ -1402,7 +1541,7 @@ __cgfsng_ops__ static bool __do_cgroup_enter(struct cgroup_ops *ops, pid_t pid,
        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);
 }
@@ -1511,7 +1650,7 @@ static int chown_cgroup_wrapper(void *data)
        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;
@@ -1544,7 +1683,7 @@ static bool cg_mount_needs_subdirs(int type)
 
 /* After $rootfs/sys/fs/container/controller/the/cg/path has been created,
  * remount controller ro if needed and bindmount the cgroupfs onto
- * controll/the/cg/path.
+ * control/the/cg/path.
  */
 static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
                                       char *controllerpath, char *cgpath,
@@ -1661,7 +1800,7 @@ static inline int cg_mount_cgroup_full(int type, struct hierarchy *h,
        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)
 {
@@ -1812,7 +1951,7 @@ static int recursive_count_nrtasks(char *dirname)
        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;
@@ -1827,7 +1966,7 @@ __cgfsng_ops__ static int cgfsng_nrtasks(struct cgroup_ops *ops)
 }
 
 /* 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;
@@ -1854,7 +1993,7 @@ __cgfsng_ops__ static bool cgfsng_escape(const struct cgroup_ops *ops,
        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;
 
@@ -1864,7 +2003,7 @@ __cgfsng_ops__ static int cgfsng_num_hierarchies(struct cgroup_ops *ops)
        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;
 
@@ -1884,7 +2023,7 @@ __cgfsng_ops__ static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n,
 /* 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;
@@ -1903,7 +2042,7 @@ __cgfsng_ops__ static bool cgfsng_unfreeze(struct cgroup_ops *ops)
        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;
@@ -1963,9 +2102,9 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
 
        free(full_path);
 
-       len = strlen(base_path) + sizeof("/lxc-1000") - 1 +
-             sizeof("/cgroup-procs") - 1;
-       full_path = must_alloc(len + 1);
+       len = strlen(base_path) + STRLITERALLEN("/lxc-1000") +
+             STRLITERALLEN("/cgroup-procs");
+       full_path = must_realloc(NULL, len + 1);
        do {
                if (idx)
                        ret = snprintf(full_path, len + 1, "%s/lxc-%d",
@@ -1988,7 +2127,8 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
                if (errno != EBUSY)
                        goto on_error;
 
-       } while (++idx > 0 && idx < 1000);
+               idx++;
+       } while (idx < 1000);
 
 on_success:
        if (idx < 1000)
@@ -2002,14 +2142,14 @@ on_error:
        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++) {
@@ -2049,7 +2189,7 @@ __cgfsng_ops__ static bool cgfsng_attach(struct cgroup_ops *ops, const char *nam
  * 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)
 {
@@ -2088,7 +2228,7 @@ __cgfsng_ops__ static int cgfsng_get(struct cgroup_ops *ops, const char *filenam
  * 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)
 {
@@ -2323,7 +2463,7 @@ static bool __cg_unified_setup_limits(struct cgroup_ops *ops,
        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)
 {
@@ -2635,7 +2775,7 @@ static bool cg_init(struct cgroup_ops *ops, struct lxc_conf *conf)
        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;
 
@@ -2647,7 +2787,7 @@ __cgfsng_ops__ static bool cgfsng_data_init(struct cgroup_ops *ops)
                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;
 }
@@ -2669,7 +2809,8 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
        }
 
        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;