summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Safranek <jsafrane@redhat.com>2009-07-29 15:17:47 +0200
committerJan Safranek <jsafrane@redhat.com>2009-07-29 15:17:47 +0200
commit67f6b94acfb1fceda2cc77aa37901293c5022df8 (patch)
treeaefaeee0aa8640bcd40eab98a6f0ec0850a8e889
parentc2cb41865e7691a615485abcb21e19536bd13148 (diff)
downloadlibcg-67f6b94acfb1fceda2cc77aa37901293c5022df8.tar.gz
libcg-67f6b94acfb1fceda2cc77aa37901293c5022df8.tar.xz
libcg-67f6b94acfb1fceda2cc77aa37901293c5022df8.zip
Add recursive cgroup_delete_cgroup_ext.
The new function allows to recursively delete whole tree of groups. There is new infrastructure created around (cg_delete_cgroup_controller_recursive). It has inconsistent behavior when root group removal is requested - it removes all children (if requested), but does not remove the root itself and returns success value. This allows simple rewrite of cgclear functions to use this function. Original cgroup_delete_cgroup now leads to cgroup_delete_cgroup_ext. Signed-off-by: Jan Safranek <jsafrane@redhat.com>
-rw-r--r--include/libcgroup.h27
-rw-r--r--src/api.c147
-rw-r--r--src/libcgroup.map6
3 files changed, 155 insertions, 25 deletions
diff --git a/include/libcgroup.h b/include/libcgroup.h
index 0942161..9b11321 100644
--- a/include/libcgroup.h
+++ b/include/libcgroup.h
@@ -130,6 +130,18 @@ struct cgroup_file_info {
*/
#define CG_HIER_MAX CG_CONTROLLER_MAX
+
+/**
+ * Ignore errors caused by migration of tasks to parent group.
+ */
+#define CGFLAG_DELETE_IGNORE_MIGRATION 1
+
+/**
+ * Recursively delete all child groups.
+ */
+#define CGFLAG_DELETE_RECURSIVE 2
+
+
struct cgroup_stat {
char name[FILENAME_MAX];
char value[CG_VALUE_MAX];
@@ -155,6 +167,21 @@ int cgroup_create_cgroup_from_parent(struct cgroup *cgroup, int ignore_ownership
int cgroup_copy_cgroup(struct cgroup *dst, struct cgroup *src);
/**
+ * Delete control group.
+ * All tasks are automatically moved to parent group.
+ * If CGFLAG_DELETE_IGNORE_MIGRATION flag is used, the errors that occurred
+ * during the task movement are ignored.
+ * CGFLAG_DELETE_RECURSIVE flag specifies that all subgroups should be removed
+ * too. If root group is being removed with this flag specified, all subgroups
+ * are removed but the root group itself is left undeleted.
+ *
+ * @param cgroup Group to delete.
+ * @param flags Combination of CGFLAG_DELETE_* flags, which indicate what and
+ * how to delete.
+ */
+int cgroup_delete_cgroup_ext(struct cgroup *cgroup, int flags);
+
+/**
* Changes the cgroup of a program based on the rules in the config file.
* If a rule exists for the given UID, GID or PROCESS NAME, then the given
* PID is placed into the correct group. By default, this function parses
diff --git a/src/api.c b/src/api.c
index c81e405..3637885 100644
--- a/src/api.c
+++ b/src/api.c
@@ -1537,12 +1537,12 @@ static int cg_move_task_files(FILE *input_tasks, FILE *output_tasks)
* @param controller Name of the controller.
* @param target_tasks Opened tasks file of the target group, where all
* processes should be moved.
- * @param ignore_migration Flag indicating whether the errors from task
- * migration should be ignored (1) or not (0).
+ * @param flags Flag indicating whether the errors from task
+ * migration should be ignored (CGROUP_DELETE_IGNORE_MIGRATION) or not (0).
* @returns 0 on success, >0 on error.
*/
static int cg_delete_cgroup_controller(char *cgroup_name, char *controller,
- FILE *target_tasks, int ignore_migration)
+ FILE *target_tasks, int flags)
{
FILE *delete_tasks = NULL;
char path[FILENAME_MAX];
@@ -1572,7 +1572,7 @@ static int cg_delete_cgroup_controller(char *cgroup_name, char *controller,
}
}
- if (ret != 0 && !ignore_migration)
+ if (ret != 0 && !(flags || CGFLAG_DELETE_IGNORE_MIGRATION))
return ret;
/*
@@ -1590,6 +1590,78 @@ static int cg_delete_cgroup_controller(char *cgroup_name, char *controller,
return 0;
}
+/**
+ * Recursively delete one control group. Moves all tasks from the group and
+ * its subgroups to given task file.
+ *
+ * @param cgroup_name The group to delete.
+ * @param controller The controller, where to delete.
+ * @param target_tasks Opened file, where all tasks should be moved.
+ * @param flags Combination of CGFLAG_DELETE_* flags. The function assumes
+ * that CGFLAG_DELETE_RECURSIVE is set.
+ * @param delete_root Whether the group itself should be removed(1) or not(0).
+ */
+static int cg_delete_cgroup_controller_recursive(char *cgroup_name,
+ char *controller, FILE *target_tasks, int flags,
+ int delete_root)
+{
+ int ret;
+ void *handle;
+ struct cgroup_file_info info;
+ int level, group_len;
+ char child_name[FILENAME_MAX];
+
+ cgroup_dbg("Recursively removing %s:%s\n", controller, cgroup_name);
+
+ ret = cgroup_walk_tree_begin(controller, cgroup_name, 0, &handle,
+ &info, &level);
+
+ if (ret == 0)
+ ret = cgroup_walk_tree_set_flags(&handle,
+ CGROUP_WALK_TYPE_POST_DIR);
+
+ if (ret != 0) {
+ cgroup_walk_tree_end(&handle);
+ return ret;
+ }
+
+ group_len = strlen(info.full_path);
+
+ /*
+ * Skip the root group, it will be handled explicitly at the end.
+ */
+ ret = cgroup_walk_tree_next(0, &handle, &info, level);
+
+ while (ret == 0) {
+ if (info.type == CGROUP_FILE_TYPE_DIR && info.depth > 0) {
+ snprintf(child_name, sizeof(child_name), "%s/%s",
+ cgroup_name,
+ info.full_path + group_len);
+
+ ret = cg_delete_cgroup_controller(child_name,
+ controller, target_tasks,
+ flags);
+ if (ret != 0)
+ break;
+ }
+
+ ret = cgroup_walk_tree_next(0, &handle, &info, level);
+ }
+ if (ret == ECGEOF) {
+ /*
+ * Iteration finished successfully, remove the root group.
+ */
+ ret = 0;
+ if (delete_root)
+ ret = cg_delete_cgroup_controller(cgroup_name,
+ controller, target_tasks,
+ flags);
+ }
+
+ cgroup_walk_tree_end(&handle);
+ return ret;
+}
+
/** cgroup_delete cgroup deletes a control group.
* struct cgroup *cgroup takes the group which is to be deleted.
*
@@ -1597,11 +1669,18 @@ static int cg_delete_cgroup_controller(char *cgroup_name, char *controller,
*/
int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
{
- FILE *base_tasks = NULL;
- char path[FILENAME_MAX];
+ int flags = ignore_migration ? CGFLAG_DELETE_IGNORE_MIGRATION : 0;
+ return cgroup_delete_cgroup_ext(cgroup, flags);
+}
+
+int cgroup_delete_cgroup_ext(struct cgroup *cgroup, int flags)
+{
+ FILE *parent_tasks = NULL;
+ char parent_path[FILENAME_MAX];
int error = 0;
int i, ret;
- char *parent_path = NULL;
+ char *parent_name = NULL;
+ int delete_group = 1;
if (!cgroup_initialized)
return ECGROUPNOTINITIALIZED;
@@ -1614,16 +1693,28 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
return ECGROUPSUBSYSNOTMOUNTED;
}
- ret = cgroup_find_parent(cgroup, &parent_path);
+ ret = cgroup_find_parent(cgroup, &parent_name);
if (ret)
return ret;
- if (parent_path == NULL) {
+ if (parent_name == NULL) {
/*
* Root group is being deleted.
- * TODO: should it succeed?
*/
- return 0;
+ if (flags & CGFLAG_DELETE_RECURSIVE) {
+ /*
+ * Move all tasks to the root group and do not delete
+ * it afterwards.
+ */
+ parent_name = strdup(".");
+ if (parent_name == NULL)
+ return ECGFAIL;
+ delete_group = 0;
+ } else
+ /*
+ * TODO: should it succeed?
+ */
+ return 0;
}
/*
@@ -1632,23 +1723,29 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
for (i = 0; i < cgroup->index; i++) {
ret = 0;
- if (!cg_build_path(parent_path, path,
+ if (!cg_build_path(parent_name, parent_path,
cgroup->controller[i]->name))
continue;
- strncat(path, "/tasks", sizeof(path) - strlen(path));
- base_tasks = fopen(path, "w");
- if (!base_tasks) {
- if (!ignore_migration) {
- last_errno = errno;
- ret = ECGOTHER;
- } else
- ret = 0;
+ strncat(parent_path, "/tasks", sizeof(parent_path)
+ - strlen(parent_path));
+
+ parent_tasks = fopen(parent_path, "w");
+ if (!parent_tasks) {
+ last_errno = errno;
+ ret = ECGOTHER;
} else {
- ret = cg_delete_cgroup_controller(cgroup->name,
- cgroup->controller[i]->name, base_tasks,
- ignore_migration);
- fclose(base_tasks);
+ if (flags & CGFLAG_DELETE_RECURSIVE)
+ ret = cg_delete_cgroup_controller_recursive(
+ cgroup->name,
+ cgroup->controller[i]->name,
+ parent_tasks, flags,
+ delete_group);
+ else
+ ret = cg_delete_cgroup_controller(cgroup->name,
+ cgroup->controller[i]->name,
+ parent_tasks, flags);
+ fclose(parent_tasks);
}
/*
@@ -1660,7 +1757,7 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
error = ret;
}
- free(parent_path);
+ free(parent_name);
return error;
}
diff --git a/src/libcgroup.map b/src/libcgroup.map
index e66c332..1072171 100644
--- a/src/libcgroup.map
+++ b/src/libcgroup.map
@@ -75,3 +75,9 @@ global:
cgroup_change_cgroup_flags;
cgroup_find_parent;
} CGROUP_0.33;
+
+CGROUP_0.35 {
+global:
+ cgroup_delete_cgroup_ext;
+}CGROUP_0.34;
+