---

 include/libcgroup/config.h |   17 +++++
 src/config.c               |  140 ++++++++++++++++++++++++++++++++++++++++++++
 src/libcgroup.map          |    1 
 3 files changed, 158 insertions(+), 0 deletions(-)

diff --git a/include/libcgroup/config.h b/include/libcgroup/config.h
index 3865603..4cf5ce0 100644
--- a/include/libcgroup/config.h
+++ b/include/libcgroup/config.h
@@ -39,6 +39,23 @@ int cgroup_config_load_config(const char *pathname);
 int cgroup_unload_cgroups(void);
 
 /**
+ * Delete all cgroups and unmount all mount points defined in specified config
+ * file.
+ *
+ * The groups are either removed recursively or only the empty ones, based
+ * on given flags. Mount point are always umounted only if they are empty,
+ * regardless of any flags.
+ *
+ * The groups are sorted before they are removed, so the removal of empty ones
+ * actually works (i.e. subgroups are removed first).
+ *
+ * @param pathname Name of the configuration file to unload.
+ * @param flags Combination of CGFLAG_DELETE_* flags, which indicate what and
+ *     how to delete.
+ */
+int cgroup_config_unload_config(const char *pathname, int flags);
+
+/**
  * @}
  * @}
  */
diff --git a/src/config.c b/src/config.c
index e71a400..8548174 100644
--- a/src/config.c
+++ b/src/config.c
@@ -798,6 +798,20 @@ err:
        return ret;
 }
 
+int _cgroup_config_compare_groups(const void *p1, const void *p2)
+{
+       const struct cgroup *g1 = p1;
+       const struct cgroup *g2 = p2;
+
+       return strcmp(g1->name, g2->name);
+}
+
+static void cgroup_config_sort_groups()
+{
+       qsort(config_cgroup_table, cgroup_table_index, sizeof(struct cgroup),
+                       _cgroup_config_compare_groups);
+}
+
 /*
  * The main function which does all the setup of the data structures
  * and finally creates the cgroups
@@ -868,6 +882,132 @@ err_mnt:
        return error;
 }
 
+/* unmounts given mount, but only if it is empty */
+static int cgroup_config_try_unmount(struct cg_mount_table_s *mount_info)
+{
+       char *controller, *controller_list;
+       struct cg_mount_point *mount = &(mount_info->mount);
+       void *handle = NULL;
+       int ret, lvl;
+       struct cgroup_file_info info;
+       char *saveptr = NULL;
+
+       /* parse the first controller name from list of controllers */
+       controller_list = strdup(mount_info->name);
+       if (!controller_list) {
+               last_errno = errno;
+               return ECGOTHER;
+       }
+       controller = strtok_r(controller_list, ",", &saveptr);
+       if (!controller) {
+               free(controller_list);
+               return ECGINVAL;
+       }
+
+       /* check if the hierarchy is empty */
+       ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl);
+       free(controller_list);
+       if (ret == ECGCONTROLLEREXISTS)
+               return 0;
+       if (ret)
+               return ret;
+       /* skip the first found directory, it's '/' */
+       ret = cgroup_walk_tree_next(0, &handle, &info, lvl);
+       /* find any other subdirectory */
+       while (ret == 0) {
+               if (info.type == CGROUP_FILE_TYPE_DIR)
+                       break;
+               ret = cgroup_walk_tree_next(0, &handle, &info, lvl);
+       }
+       cgroup_walk_tree_end(&handle);
+       if (ret == 0) {
+               cgroup_dbg("won't unmount %s: hieararchy is not empty\n",
+                               mount_info->name);
+               return 0; /* the hieararchy is not empty */
+       }
+       if (ret != ECGEOF)
+               return ret;
+
+
+       /*
+        * ret must be ECGEOF now = there is only root group in the hierarchy
+        * -> unmount all mount points.
+        */
+       ret = 0;
+       while (mount) {
+               int err;
+               cgroup_dbg("unmounting %s at %s\n", mount_info->name,
+                               mount->path);
+               err = umount(mount->path);
+
+               if (err && !ret) {
+                       ret = ECGOTHER;
+                       last_errno = errno;
+               }
+               mount = mount->next;
+       }
+       return ret;
+}
+
+int cgroup_config_unload_config(const char *pathname, int flags)
+{
+       int ret, i, error;
+       int namespace_enabled = 0;
+       int mount_enabled = 0;
+
+       cgroup_dbg("cgroup_config_unload_config: parsing %s\n", pathname);
+       ret = cgroup_parse_config(pathname);
+       if (ret)
+               goto err;
+
+       namespace_enabled = (config_namespace_table[0].name[0] != '\0');
+       mount_enabled = (config_mount_table[0].name[0] != '\0');
+       /*
+        * The configuration should have namespace or mount, not both.
+        */
+       if (namespace_enabled && mount_enabled) {
+               free(config_cgroup_table);
+               return ECGMOUNTNAMESPACE;
+       }
+
+       ret = config_order_namespace_table();
+       if (ret)
+               goto err;
+
+       ret = config_validate_namespaces();
+       if (ret)
+               goto err;
+
+       /*
+        * Delete the groups in reverse order, i.e. subgroups first, then
+        * parents.
+        */
+       cgroup_config_sort_groups();
+       for (i = cgroup_table_index-1; i >= 0; i--) {
+               struct cgroup *cgroup = &config_cgroup_table[i];
+               cgroup_dbg("removing %s\n", pathname);
+               error = cgroup_delete_cgroup_ext(cgroup, flags);
+               if (error && !ret) {
+                       /* store the error, but continue deleting the rest */
+                       ret = error;
+               }
+       }
+
+       if (mount_enabled) {
+               for (i = 0; i < config_table_index; i++) {
+                       struct cg_mount_table_s *m = &(config_mount_table[i]);
+                       cgroup_dbg("unmounting %s\n", m->name);
+                       error = cgroup_config_try_unmount(m);
+                       if (error && !ret)
+                               ret = error;
+               }
+       }
+
+err:
+       cgroup_free_config();
+       return ret;
+}
+
 static int cgroup_config_unload_controller(const struct cgroup_mount_point 
*mount_info)
 {
        int ret, error;
diff --git a/src/libcgroup.map b/src/libcgroup.map
index f1afaf6..7a0927e 100644
--- a/src/libcgroup.map
+++ b/src/libcgroup.map
@@ -102,4 +102,5 @@ CGROUP_0.38 {
        cgroup_get_subsys_mount_point_next;
        cgroup_get_subsys_mount_point_end;
        cgroup_set_permissions;
+       cgroup_config_unload_config;
 } CGROUP_0.37;


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2dcopy2
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to