]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
libcgroup: Introduce a unload cgroups API
authorDhaval Giani <dhaval@linux.vnet.ibm.com>
Mon, 22 Jun 2009 11:50:09 +0000 (17:20 +0530)
committerDhaval Giani <dhaval@linux.vnet.ibm.com>
Mon, 22 Jun 2009 11:50:09 +0000 (17:20 +0530)
This API will unload the cgroups created in the cgroupfs and
unmount and delete the filesystem mount point. The action is
equivalent to what is done currently in service cgconfig stop.

The reason for this API is to make sure we don't end up with a
asymmetric library API subset. Today an application program can
programatically through cgroup_config_load_config() load a
configuration file, but has no means to cleanup (including all
temporarily created groups).

changes from v3
1. Address Jan's comments from http://article.gmane.org/gmane.comp.lib.libcg.devel/1105
changes from v2
1. Fix a leak as noted by Bharata
2. Address Balbir's review comments at
http://article.gmane.org/gmane.comp.lib.libcg.devel/1080
changes from v1
1. Change the name of the function to cgroup_unload_cgroups
2. Change the name of the executatble to cgclear
3. Split out the funtions

Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com>
include/libcgroup.h
src/config.c
src/libcgroup.map
src/tools/Makefile.am
src/tools/cgclear.c [new file with mode: 0644]

index e2abdc8701df886220733f1d1ac81feb1805c916..ce0d8a5b41cd05c9a545d5d70ecb1d279996054d 100644 (file)
@@ -368,6 +368,7 @@ struct cgroup_controller *cgroup_get_controller(struct cgroup *cgroup,
  * Config related stuff
  */
 int cgroup_config_load_config(const char *pathname);
+int cgroup_unload_cgroups(void);
 
 __END_DECLS
 
index 5706e1dd6fe2236ba19a06e4bc6b0835dc3af9b1..5d5155f81f88e27d85bb2e290ae2ac84fbd3cd67 100644 (file)
@@ -492,3 +492,177 @@ err_mnt:
        fclose(yyin);
        return error;
 }
+
+static int cgroup_cleanup_cgroup_controller_files(struct cgroup_file_info info,
+                                               char *root_path, char *ctrl)
+{
+       void *task_handle;
+       pid_t pid;
+       char *rel_path = NULL;
+       int error;
+       int ret;
+
+
+       rel_path = info.full_path + strlen(root_path) - 1;
+
+       if (!strncmp(rel_path, "/", strlen(rel_path)))
+               return 0;
+
+       error = cgroup_get_task_begin(rel_path, ctrl,
+                                       &task_handle, &pid);
+
+       if (error && error != ECGEOF)
+               return error;
+
+       while (error != ECGEOF) {
+               ret = cgroup_attach_task_pid(NULL, pid);
+
+               if (ret) {
+                       cgroup_get_task_end(&task_handle);
+                       return ret;
+               }
+               error = cgroup_get_task_next(&task_handle, &pid);
+
+               if (error && error != ECGEOF) {
+                       cgroup_get_task_end(&task_handle);
+                       return error;
+               }
+       }
+
+       cgroup_get_task_end(&task_handle);
+
+       error = rmdir(info.full_path);
+       if (error) {
+               last_errno = errno;
+               return ECGOTHER;
+       }
+
+       return 0;
+}
+
+static int cgroup_config_unload_controller(struct cgroup_mount_point mount_info)
+{
+       struct cgroup_file_info info;
+       void *tree_handle;
+       int lvl;
+       int ret = 0, error;
+       char *root_path = NULL;
+
+       error = cgroup_walk_tree_begin(mount_info.name, "/", 0, &tree_handle,
+                                                       &info, &lvl);
+
+       if (error && error != ECGEOF)
+               return error;
+
+       root_path = strdup(info.full_path);
+
+       if (!root_path) {
+               cgroup_walk_tree_end(&tree_handle);
+               last_errno = errno;
+               return ECGOTHER;
+       }
+
+       ret = cgroup_walk_tree_set_flags(&tree_handle,
+                               CGROUP_WALK_TYPE_POST_DIR);
+
+       if (ret) {
+               cgroup_walk_tree_end(&tree_handle);
+               goto out_error;
+       }
+
+       while (error != ECGEOF) {
+               if (info.type == CGROUP_FILE_TYPE_DIR) {
+                       ret = cgroup_cleanup_cgroup_controller_files(info,
+                                               root_path, mount_info.name);
+
+                       if (ret) {
+                               cgroup_walk_tree_end(&tree_handle);
+                               goto out_error;
+                       }
+               }
+
+               error = cgroup_walk_tree_next(0, &tree_handle, &info, lvl);
+
+               if (error && error != ECGEOF) {
+                       ret = error;
+                       cgroup_walk_tree_end(&tree_handle);
+               }
+       }
+       cgroup_walk_tree_end(&tree_handle);
+       error = umount(mount_info.path);
+
+       if (error) {
+               last_errno = errno;
+               ret = ECGOTHER;
+               goto out_error;
+       }
+
+       error = rmdir(mount_info.path);
+
+       if (error) {
+               last_errno = errno;
+               ret = ECGOTHER;
+       }
+
+out_error:
+       free(root_path);
+       return ret;
+}
+
+int cgroup_unload_cgroups(void)
+{
+       int error = 0;
+       void *ctrl_handle;
+       int ret = 0;
+       char *curr_path = NULL;
+       struct cgroup_mount_point info;
+
+       error = cgroup_init();
+
+       if (error) {
+               ret = error;
+               goto out_error;
+       }
+
+       error = cgroup_get_controller_begin(&ctrl_handle, &info);
+
+
+       if (error && error != ECGEOF) {
+               ret = error;
+               goto out_error;
+       }
+
+       while (error != ECGEOF) {
+               if (!curr_path || strcmp(info.path, curr_path) != 0) {
+                       if (curr_path)
+                               free(curr_path);
+
+                       curr_path = strdup(info.path);
+                       if (!curr_path)
+                               goto out_errno;
+
+                       ret = cgroup_config_unload_controller(info);
+
+                       if (ret)
+                               goto out_error;
+               }
+
+               error = cgroup_get_controller_next(&ctrl_handle, &info);
+
+               if (error && error != ECGEOF) {
+                       ret = error;
+                       goto out_error;
+               }
+       }
+
+out_error:
+       if (curr_path)
+               free(curr_path);
+       cgroup_get_controller_end(&ctrl_handle);
+       return ret;
+
+out_errno:
+       last_errno = errno;
+       cgroup_get_controller_end(&ctrl_handle);
+       return ECGOTHER;
+}
index adcf9059e295f5f9d7e5762ad355a3eb8bf95da0..5b088d4b42469cc1c0e78a45e707584f0112a635 100644 (file)
@@ -66,6 +66,7 @@ global:
        cgroup_get_controller_end;
        cgroup_get_controller_next;
        cgroup_get_controller_begin;
+       cgroup_unload_cgroups;
        cgroup_get_controller;
        cgroup_get_uid_gid_from_procfs;
 } CGROUP_0.33;
index 2b4c9e7cdcf7caf1cad426e87a8321d7b62cec88..f82916c63a8a7016152ccc59496ee8460364267f 100644 (file)
@@ -5,7 +5,7 @@ if WITH_TOOLS
 
 bin_PROGRAMS = cgexec cgclassify cgcreate cgset
 
-sbin_PROGRAMS = cgconfigparser
+sbin_PROGRAMS = cgconfigparser cgclear
 
 cgexec_SOURCES = cgexec.c tools-common.c tools-common.h
 
@@ -15,4 +15,6 @@ cgcreate_SOURCES = cgcreate.c tools-common.c tools-common.h
 
 cgconfigparser_SOURCES = cgconfig.c
 
+cgclear_SOURCES = cgclear.c
+
 endif
diff --git a/src/tools/cgclear.c b/src/tools/cgclear.c
new file mode 100644 (file)
index 0000000..1485768
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright IBM Corporation. 2009
+ *
+ * Authors:    Dhaval Giani <dhaval@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Code initiated and designed by Dhaval Giani. All faults are most likely
+ * his mistake.
+ */
+
+#include <libcgroup.h>
+#include <libcgroup-internal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+       int error;
+
+       error = cgroup_unload_cgroups();
+
+       if (error) {
+               printf("%s failed with %s\n", argv[0], cgroup_strerror(error));
+               exit(3);
+       }
+
+       return 0;
+}