As same as normal directories, a cgroup cannot be removed if it
contains sub groups. This patch changes virCgroupRemove to remove
all child groups (subdirectories) of a target group before removing
the target group.
The handling is required when we run lxc with ns subsystem of cgroup.
Ns subsystem automatically creates child cgroups on every process
forks, but unfortunately the groups are not removed on process exits,
so we have to remove them by ourselves.
With this patch, such child groups are surely removed at lxc
shutdown, i.e., lxcVmCleanup which calls virCgroupRemove.
---
src/util/cgroup.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index b8b2eb5..531c131 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -23,6 +23,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <libgen.h>
+#include <dirent.h>
#include "internal.h"
#include "util.h"
@@ -561,11 +562,52 @@ cleanup:
}
#endif
+static int virCgroupRemoveRecursively(char *grppath)
+{
+ DIR *grpdir;
+ struct dirent *ent;
+ int rc = 0;
+
+ grpdir = opendir(grppath);
+ if (grpdir == NULL) {
+ VIR_ERROR("Unable to open %s (%d)", grppath, errno);
+ rc = -errno;
+ return rc;
+ }
+
+ while ((ent = readdir(grpdir)) != NULL) {
+ char path[PATH_MAX];
+ int ret;
+
+ if (ent->d_name[0] == '.') continue;
+ if (ent->d_type != DT_DIR) continue;
+
+ ret = snprintf(path, sizeof(path), "%s/%s", grppath, ent->d_name);
+ if (ret < 0)
+ break;
+ rc = virCgroupRemoveRecursively(path);
+ if (rc != 0)
+ break;
+ }
+ DEBUG("Removing cgroup %s", grppath);
+ if (rmdir(grppath) != 0 && errno != ENOENT) {
+ rc = -errno;
+ VIR_ERROR("Unable to remove %s (%d)", grppath, errno);
+ }
+
+ return rc;
+}
+
/**
* virCgroupRemove:
*
* @group: The group to be removed
*
+ * It first removes all child groups recursively
+ * in depth first order and then removes @group
+ * because the presence of the child groups
+ * prevents removing @group.
+ *
* Returns: 0 on success
*/
int virCgroupRemove(virCgroupPtr group)
@@ -585,10 +627,8 @@ int virCgroupRemove(virCgroupPtr group)
&grppath) != 0)
continue;
- DEBUG("Removing cgroup %s", grppath);
- if (rmdir(grppath) != 0 && errno != ENOENT) {
- rc = -errno;
- }
+ DEBUG("Removing cgroup %s and all child cgroups", grppath);
+ rc = virCgroupRemoveRecursively(grppath);
VIR_FREE(grppath);
}
--
1.6.5.2