[libvirt] [RFC PATCH v1 5/7] cgroup: refactor virCgroup

Hu Tao hutao at cn.fujitsu.com
Wed Jan 16 02:53:07 UTC 2013


This patch adds a new structure, virCgroupItem, to represent
a cgroup directory(named cgroup item). cgroup directory is
created when needed and removed if no one is using it.
---
 src/libvirt_private.syms |   7 +
 src/util/vircgroup.c     | 411 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/util/vircgroup.h     |  12 ++
 3 files changed, 423 insertions(+), 7 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7be58ee..636c49d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -104,6 +104,12 @@ virCgroupGetMemorySoftLimit;
 virCgroupGetMemoryUsage;
 virCgroupGetMemSwapHardLimit;
 virCgroupGetMemSwapUsage;
+virCgroupInit;
+virCgroupItemFree;
+virCgroupItemKeyPath;
+virCgroupItemNew;
+virCgroupItemPath;
+virCgroupItemType;
 virCgroupKill;
 virCgroupKillPainfully;
 virCgroupKillRecursive;
@@ -123,6 +129,7 @@ virCgroupSetMemory;
 virCgroupSetMemoryHardLimit;
 virCgroupSetMemorySoftLimit;
 virCgroupSetMemSwapHardLimit;
+virCgroupUninit;
 
 
 # command.h
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 71d46c5..baa0af7 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -37,6 +37,7 @@
 #include <libgen.h>
 #include <dirent.h>
 
+#include "virobject.h"
 #include "internal.h"
 #include "virutil.h"
 #include "viralloc.h"
@@ -45,6 +46,7 @@
 #include "virfile.h"
 #include "virhash.h"
 #include "virhashcode.h"
+#include "virthread.h"
 
 #define CGROUP_MAX_VAL 512
 
@@ -58,6 +60,98 @@ struct virCgroupController {
     char *placement;
 };
 
+struct _virCgroupItem {
+    virObject object;
+
+    char *name;
+    char *path;
+
+    bool created;          /* the path is created or not */
+
+    virCgroupItemPtr next;
+    virCgroupItemPtr parent;
+    virCgroupItemPtr children;
+
+    struct virCgroupController *controller;
+};
+
+static virClassPtr cgroupItemClass;
+
+static void cgroupItemDispose(void *obj);
+
+static int virCgroupItemOnceInit(void)
+{
+    if (!(cgroupItemClass = virClassNew("cgroupItem",
+                                        sizeof(virCgroupItem),
+                                        cgroupItemDispose)))
+        return -1;
+
+    return 0;
+}
+VIR_ONCE_GLOBAL_INIT(virCgroupItem);
+
+static struct virCgroupController cgroupControllers[VIR_CGROUP_CONTROLLER_LAST];
+static virCgroupItemPtr rootCgroupItems[VIR_CGROUP_CONTROLLER_LAST];
+
+static virCgroupItemPtr virCgroupItemRootNew(int type);
+static int virCgroupDetectMounts(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST]);
+static int virCgroupDetectPlacement(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST]);
+
+int virCgroupInit(void)
+{
+    int rc;
+    int i;
+
+    rc = virCgroupDetectMounts(&cgroupControllers);
+    if (rc < 0) {
+        VIR_ERROR(_("Failed to initialize cgroup controllers"));
+        return rc;
+    }
+
+    rc = virCgroupDetectPlacement(&cgroupControllers);
+
+    if (rc == 0) {
+        /* Check that for every mounted controller, we found our placement */
+        for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+            if (!cgroupControllers[i].mountPoint)
+                continue;
+
+            if (!cgroupControllers[i].placement) {
+                VIR_ERROR(_("Could not find placement for controller %s at %s"),
+                          virCgroupControllerTypeToString(i),
+                          cgroupControllers[i].placement);
+                rc = -ENOENT;
+                break;
+            }
+
+            VIR_DEBUG("Detected mount/mapping %i:%s at %s in %s", i,
+                      virCgroupControllerTypeToString(i),
+                      cgroupControllers[i].mountPoint,
+                      cgroupControllers[i].placement);
+        }
+    } else {
+        VIR_ERROR(_("Failed to initialize cgroup controllers"));
+    }
+
+    for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+        rootCgroupItems[i] = virCgroupItemRootNew(i);
+    }
+
+    return rc;
+}
+
+void virCgroupUninit(void)
+{
+    int i;
+
+    for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+        if (rootCgroupItems[i]) {
+            virCgroupItemFree(rootCgroupItems[i]);
+            rootCgroupItems[i] = NULL;
+        }
+    }
+}
+
 struct virCgroup {
     char *path;
 
@@ -74,6 +168,307 @@ typedef enum {
                                * cpuacct and cpuset if possible. */
 } virCgroupFlags;
 
+static virCgroupItemPtr virCgroupItemRootNew(int type)
+{
+    virCgroupItemPtr rootItem = NULL;
+
+    if (type >= VIR_CGROUP_CONTROLLER_LAST)
+        return NULL;
+
+    if (!cgroupControllers[type].mountPoint)
+        return NULL;
+
+    if (virCgroupItemInitialize() < 0)
+        return NULL;
+
+    if (!(rootItem = virObjectNew(cgroupItemClass)))
+        return NULL;
+
+    rootItem->name = strdup("/");
+    rootItem->next = NULL;
+    rootItem->parent = NULL;
+    rootItem->children = NULL;
+    rootItem->controller = &cgroupControllers[type];
+    rootItem->created = 1;
+
+    if (virAsprintf(&rootItem->path, "%s%s%s",
+                    rootItem->controller->mountPoint,
+                    rootItem->controller->placement,
+                    rootItem->name) == -1) {
+        virObjectUnref(rootItem);
+        rootItem = NULL;
+    }
+
+    return rootItem;
+}
+
+static virCgroupItemPtr virCgroupHasChildByName(virCgroupItemPtr item,
+                                                const char *name)
+{
+    virCgroupItemPtr child = item->children;
+
+    while (child) {
+        if (STREQ(child->name, name)) {
+            virObjectRef(child);
+            return child;
+        }
+
+        child = child->next;
+    }
+
+    return NULL;
+}
+
+virCgroupItemPtr virCgroupItemNew(int type,
+                                  const char *name,
+                                  virCgroupItemPtr parent)
+{
+    virCgroupItemPtr cgroupItem = NULL;
+    virCgroupItemPtr *next = NULL;
+
+    if (type >= VIR_CGROUP_CONTROLLER_LAST)
+        return NULL;
+
+    if (virCgroupItemInitialize() < 0)
+        return NULL;
+
+    if (!cgroupControllers[type].mountPoint)
+        return NULL;
+
+    if (!parent)
+        parent = rootCgroupItems[type];
+
+    if (!parent)
+        return NULL;
+
+    cgroupItem = virCgroupHasChildByName(parent, name);
+    if (cgroupItem)
+        return cgroupItem;
+
+    if (!(cgroupItem = virObjectNew(cgroupItemClass)))
+        return NULL;
+
+    cgroupItem->name = strdup(name);
+    cgroupItem->parent = parent;
+    cgroupItem->next = NULL;
+    cgroupItem->children = NULL;
+    cgroupItem->controller = parent->controller;
+    cgroupItem->created = false;
+
+    if (virAsprintf(&cgroupItem->path, "%s/%s",
+                    parent->path,
+                    cgroupItem->name) == -1) {
+        virObjectUnref(cgroupItem);
+        cgroupItem = NULL;
+        return NULL;
+    }
+
+    virObjectRef(cgroupItem->parent);
+
+    next = &parent->children;
+
+    while (*next)
+        next = &(*next)->next;
+
+    *next = cgroupItem;
+
+    return cgroupItem;
+}
+
+void virCgroupItemFree(virCgroupItemPtr cgroupItem)
+{
+    virObjectUnref(cgroupItem);
+}
+
+static void cgroupItemDispose(void *obj)
+{
+    virCgroupItemPtr cgroupItem = obj;
+    virCgroupItemPtr parent = cgroupItem->parent;
+    virCgroupItemPtr *next;
+
+    sa_assert(cgroupItem->children == NULL);
+
+    if (cgroupItem->created &&
+        access(cgroupItem->path, F_OK) == 0)
+        rmdir(cgroupItem->path);
+
+    if (cgroupItem->parent) {
+        next = &parent->children;
+
+        while (*next && *next != cgroupItem)
+            next = &(*next)->next;
+
+        if (*next == cgroupItem) {
+            *next = cgroupItem->next;
+            cgroupItem->next = NULL;
+            cgroupItem->parent = NULL;
+            virObjectUnref(parent);
+        }
+    }
+
+    VIR_FREE(cgroupItem->name);
+}
+
+int virCgroupItemType(virCgroupItemPtr cgroupItem)
+{
+    return cgroupItem->controller->type;
+}
+
+static int virCgroupItemGetValueStr(virCgroupItemPtr cgroupItem,
+                                    const char *key,
+                                    char **value)
+{
+    int rc;
+    char *keypath = NULL;
+
+    *value = NULL;
+
+    rc = virCgroupItemKeyPath(cgroupItem, key, &keypath);
+    if (rc != 0)
+        return rc;
+
+    VIR_DEBUG("Get value %s", keypath);
+
+    rc = virFileReadAll(keypath, 1024*1024, value);
+    if (rc < 0) {
+        rc = -errno;
+        VIR_DEBUG("Failed to read %s: %m\n", keypath);
+    } else {
+        /* Terminated with '\n' has sometimes harmful effects to the caller */
+        if ((*value)[rc - 1] == '\n')
+            (*value)[rc - 1] = '\0';
+
+        rc = 0;
+    }
+
+    VIR_FREE(keypath);
+
+    return rc;
+}
+
+static int virCgroupItemSetValueStr(virCgroupItemPtr cgroupItem,
+                                    const char *key,
+                                    const char *value)
+{
+    int rc = 0;
+    char *keypath = NULL;
+
+    rc = virCgroupItemKeyPath(cgroupItem, key, &keypath);
+    if (rc != 0)
+        return rc;
+
+    VIR_DEBUG("Set value '%s' to '%s'", keypath, value);
+    rc = virFileWriteStr(keypath, value, 0);
+    if (rc < 0) {
+        rc = -errno;
+        VIR_DEBUG("Failed to write value '%s': %m", value);
+    } else {
+        rc = 0;
+    }
+
+    VIR_FREE(keypath);
+    return rc;
+}
+
+static int virCgroupItemCpusetInherit(virCgroupItemPtr cgroupItem)
+{
+    int i;
+    char *value;
+    int rc = 0;
+    const char *inherit_values[] = {
+        "cpuset.cpus",
+        "cpuset.mems",
+    };
+
+    for (i = 0; i < ARRAY_CARDINALITY(inherit_values) ; i++) {
+        rc = virCgroupItemGetValueStr(cgroupItem->parent,
+                                      inherit_values[i],
+                                      &value);
+        if (rc != 0) {
+            VIR_ERROR(_("Failed to get %s %d"), inherit_values[i], rc);
+            break;
+        }
+
+        VIR_DEBUG("Inherit %s = %s", inherit_values[i], value);
+
+        rc = virCgroupItemSetValueStr(cgroupItem,
+                                      inherit_values[i],
+                                      value);
+        VIR_FREE(value);
+
+        if (rc != 0) {
+            VIR_ERROR(_("Failed to set %s %d"), inherit_values[i], rc);
+            break;
+        }
+    }
+
+    return rc;
+}
+
+static int virCgroupRemoveRecursively(char *grppath);
+
+static int virCgroupItemMakePath(virCgroupItemPtr cgroupItem)
+{
+    int ret = 0;
+
+    if (!cgroupItem->created && access(cgroupItem->path, F_OK) == 0) {
+        if (virCgroupRemoveRecursively(cgroupItem->path) != 0) {
+            VIR_ERROR(_("failed to remove historical cgroup directory: %s"),
+                      cgroupItem->path);
+            return -errno;
+        }
+    }
+
+    cgroupItem->created = true;
+
+    if (access(cgroupItem->path, F_OK) != 0) {
+        if (cgroupItem->parent &&
+            (ret = virCgroupItemMakePath(cgroupItem->parent)) < 0)
+            return ret;
+
+        if (mkdir(cgroupItem->path, 0755) < 0) {
+            return -errno;
+        }
+
+        virCgroupItemCpusetInherit(cgroupItem);
+    }
+
+    return ret;
+}
+
+int virCgroupItemPath(virCgroupItemPtr cgroupItem,
+                      bool create,
+                      char **path)
+{
+    if (virAsprintf(path, "%s", cgroupItem->path) == -1)
+        return -ENOMEM;
+
+    if (create && virCgroupItemMakePath(cgroupItem) < 0) {
+            VIR_FREE(*path);
+            return -1;
+    }
+
+    return 0;
+}
+
+int virCgroupItemKeyPath(virCgroupItemPtr cgroupItem,
+                         const char *key,
+                         char **path)
+{
+    int ret = 0;
+    char *cgroupItemPath = NULL;
+
+    ret = virCgroupItemPath(cgroupItem, 1, &cgroupItemPath);
+    if (ret < 0)
+        return ret;
+
+    if (virAsprintf(path, "%s/%s", cgroupItemPath, key) == -1)
+        ret = -ENOMEM;
+
+    VIR_FREE(cgroupItemPath);
+    return ret;
+}
+
 /**
  * virCgroupFree:
  *
@@ -134,6 +529,7 @@ static int virCgroupDetectMounts(struct virCgroupController (*controllers)[VIR_C
             const char *typestr = virCgroupControllerTypeToString(i);
             int typelen = strlen(typestr);
             char *tmp = entry.mnt_opts;
+            (*controllers)[i].type = i;
             while (tmp) {
                 char *next = strchr(tmp, ',');
                 int len;
@@ -171,7 +567,7 @@ no_memory:
  * sub-path the current process is assigned to. ie not
  * necessarily in the root
  */
-static int virCgroupDetectPlacement(struct virCgroupController (*cgroupControllers)[VIR_CGROUP_CONTROLLER_LAST])
+static int virCgroupDetectPlacement(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST])
 {
     int i;
     FILE *mapping  = NULL;
@@ -184,24 +580,24 @@ static int virCgroupDetectPlacement(struct virCgroupController (*cgroupControlle
     }
 
     while (fgets(line, sizeof(line), mapping) != NULL) {
-        char *controllers = strchr(line, ':');
-        char *path = controllers ? strchr(controllers+1, ':') : NULL;
+        char *controllersStr = strchr(line, ':');
+        char *path = controllersStr ? strchr(controllersStr+1, ':') : NULL;
         char *nl = path ? strchr(path, '\n') : NULL;
 
-        if (!controllers || !path)
+        if (!controllersStr || !path)
             continue;
 
         if (nl)
             *nl = '\0';
 
         *path = '\0';
-        controllers++;
+        controllersStr++;
         path++;
 
         for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
             const char *typestr = virCgroupControllerTypeToString(i);
             int typelen = strlen(typestr);
-            char *tmp = controllers;
+            char *tmp = controllersStr;
             while (tmp) {
                 char *next = strchr(tmp, ',');
                 int len;
@@ -212,7 +608,7 @@ static int virCgroupDetectPlacement(struct virCgroupController (*cgroupControlle
                     len = strlen(tmp);
                 }
                 if (typelen == len && STREQLEN(typestr, tmp, len) &&
-                    !((*cgroupControllers)[i].placement = strdup(STREQ(path, "/") ? "" : path)))
+                    !((*controllers)[i].placement = strdup(STREQ(path, "/") ? "" : path)))
                     goto no_memory;
 
                 tmp = next;
@@ -230,6 +626,7 @@ no_memory:
 
 }
 
+
 static int virCgroupDetect(virCgroupPtr group)
 {
     int any = 0;
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index 05f2e54..0ba2430 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -30,6 +30,9 @@
 struct virCgroup;
 typedef struct virCgroup *virCgroupPtr;
 
+typedef struct _virCgroupItem virCgroupItem;
+typedef virCgroupItem *virCgroupItemPtr;
+
 enum {
     VIR_CGROUP_CONTROLLER_CPU,
     VIR_CGROUP_CONTROLLER_CPUACCT,
@@ -166,4 +169,13 @@ int virCgroupKill(virCgroupPtr group, int signum);
 int virCgroupKillRecursive(virCgroupPtr group, int signum);
 int virCgroupKillPainfully(virCgroupPtr group);
 
+virCgroupItemPtr virCgroupItemNew(int type, const char *name, virCgroupItemPtr parent);
+void virCgroupItemFree(virCgroupItemPtr cgroupItem);
+int virCgroupItemType(virCgroupItemPtr cgroupItem);
+int virCgroupItemPath(virCgroupItemPtr cgroupItem, bool create, char **path);
+int virCgroupItemKeyPath(virCgroupItemPtr cgroupItem, const char *key, char **path);
+
+int virCgroupInit(void);
+void virCgroupUninit(void);
+
 #endif /* __VIR_CGROUP_H__ */
-- 
1.8.0.1.240.ge8a1f5a




More information about the libvir-list mailing list