[PATCH v2 2/5] cgroup: refactor virCgroup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 |   2 +
 src/util/vircgroup.c     | 541 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/util/vircgroup.h     |   8 +
 3 files changed, 545 insertions(+), 6 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c589236..f5138af 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -73,6 +73,8 @@ virCapabilitiesSetMacPrefix;
 
 
 # cgroup.h
+virCgroup2Free;
+virCgroup2New;
 virCgroupAddTask;
 virCgroupAddTaskController;
 virCgroupAllowDevice;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 71d46c5..dbc9688 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,91 @@ struct virCgroupController {
     char *placement;
 };
 
+struct _virCgroupItem;
+typedef struct _virCgroupItem virCgroupItem;
+typedef virCgroupItem *virCgroupItemPtr;
+
+struct _virCgroupItem {
+    virObjectLockable object;
+
+    char *name;
+    char *path;
+
+    bool created;          /* the path is created or not */
+
+    virCgroupItemPtr next;
+    virCgroupItemPtr parent;
+    virCgroupItemPtr children;
+
+    int type;
+    struct virCgroupController controllers[VIR_CGROUP_CONTROLLER_LAST];
+};
+
+struct virCgroup2 {
+    virCgroupItemPtr items[VIR_CGROUP_CONTROLLER_LAST];
+};
+
+static virClassPtr cgroupItemClass;
+
+static void cgroupItemDispose(void *obj);
+
+static int virCgroupItemOnceInit(void)
+{
+    if (!(cgroupItemClass = virClassNew(virClassForObjectLockable(),
+                                        "cgroupItem",
+                                        sizeof(virCgroupItem),
+                                        cgroupItemDispose)))
+        return -1;
+
+    return 0;
+}
+VIR_ONCE_GLOBAL_INIT(virCgroupItem);
+
+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]);
+
+static int virCgroupControllersInit(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST])
+{
+    int rc;
+    int i;
+
+    rc = virCgroupDetectMounts(controllers);
+    if (rc < 0) {
+        VIR_ERROR(_("Failed to initialize cgroup controllers"));
+        return rc;
+    }
+
+    rc = virCgroupDetectPlacement(controllers);
+
+    if (rc == 0) {
+        /* Check that for every mounted controller, we found our placement */
+        for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+            if (!(*controllers)[i].mountPoint)
+                continue;
+
+            if (!(*controllers)[i].placement) {
+                VIR_ERROR(_("Could not find placement for controller %s at %s"),
+                          virCgroupControllerTypeToString(i),
+                          (*controllers)[i].placement);
+                rc = -ENOENT;
+                break;
+            }
+
+            VIR_DEBUG("Detected mount/mapping %i:%s at %s in %s", i,
+                      virCgroupControllerTypeToString(i),
+                      (*controllers)[i].mountPoint,
+                      (*controllers)[i].placement);
+        }
+    } else {
+        VIR_ERROR(_("Failed to initialize cgroup controllers"));
+    }
+
+    return rc;
+}
+
 struct virCgroup {
     char *path;
 
@@ -74,6 +161,362 @@ typedef enum {
                                * cpuacct and cpuset if possible. */
 } virCgroupFlags;
 
+static virCgroupItemPtr virCgroupItemRootNew(int type)
+{
+    virCgroupItemPtr rootItem = NULL;
+
+    if (type >= VIR_CGROUP_CONTROLLER_LAST || type < 0)
+        return NULL;
+
+    if (virCgroupItemInitialize() < 0)
+        return NULL;
+
+    if (!(rootItem = virObjectNew(cgroupItemClass)))
+        return NULL;
+
+    if (virCgroupControllersInit(&rootItem->controllers) != 0) {
+        virObjectUnref(rootItem);
+        rootItem = NULL;
+        return NULL;
+    }
+
+    rootItem->name = strdup("/");
+    rootItem->next = NULL;
+    rootItem->parent = NULL;
+    rootItem->children = NULL;
+    rootItem->created = 1;
+    rootItem->type = type;
+    if (virAsprintf(&rootItem->path, "%s%s",
+                    rootItem->controllers[rootItem->type].mountPoint,
+                    rootItem->controllers[rootItem->type].placement) < 0) {
+        virObjectUnref(rootItem);
+        rootItem = NULL;
+    }
+
+    return rootItem;
+}
+
+static virCgroupItemPtr virCgroupHasChildByName(virCgroupItemPtr item,
+                                                const char *name)
+{
+    virCgroupItemPtr child;
+
+    virObjectLock(item);
+
+    child = item->children;
+
+    while (child) {
+        if (STREQ(child->name, name)) {
+            virObjectRef(child);
+            goto out;
+        }
+
+        child = child->next;
+    }
+
+out:
+    virObjectUnlock(item);
+    return child;
+}
+
+static virCgroupItemPtr virCgroupItemNew(const char *name,
+                                         virCgroupItemPtr parent)
+{
+    virCgroupItemPtr cgroupItem = NULL;
+    virCgroupItemPtr *next = NULL;
+
+    if (!parent)
+        return NULL;
+
+    if (virCgroupItemInitialize() < 0)
+        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->created = false;
+    cgroupItem->type = parent->type;
+
+    if (virAsprintf(&cgroupItem->path, "%s/%s",
+                    parent->path,
+                    cgroupItem->name) == -1) {
+        virObjectUnref(cgroupItem);
+        cgroupItem = NULL;
+        return NULL;
+    }
+
+    virObjectRef(parent);
+
+    virObjectLock(parent);
+
+    next = &parent->children;
+
+    while (*next)
+        next = &(*next)->next;
+
+    *next = cgroupItem;
+
+    virObjectUnlock(parent);
+
+    return cgroupItem;
+}
+
+static void virCgroupItemFree(virCgroupItemPtr *cgroupItem)
+{
+    if (!virObjectUnref(*cgroupItem))
+        *cgroupItem = NULL;
+}
+
+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);
+    VIR_FREE(cgroupItem->path);
+
+    if (parent) {
+        virObjectLock(parent);
+
+        next = &parent->children;
+
+        while (*next && *next != cgroupItem)
+            next = &(*next)->next;
+
+        if (*next == cgroupItem) {
+            *next = cgroupItem->next;
+            cgroupItem->next = NULL;
+            cgroupItem->parent = NULL;
+        } else {
+            /* BUG */
+        }
+
+        virObjectUnlock(parent);
+        virObjectUnref(parent);
+    }
+
+    VIR_FREE(cgroupItem->name);
+}
+
+static int virCgroupItemKeyPath(virCgroupItemPtr cgroupItem,
+                                const char *key,
+                                char **path);
+
+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 virCgroupRemoveRecursively(char *grppath);
+static int virCgroupItemCpusetInherit(virCgroupItemPtr cgroupItem);
+static int virCgroupItemSetMemoryUseHierarchy(virCgroupItemPtr item);
+
+static int virCgroupItemMakePath(virCgroupItemPtr cgroupItem)
+{
+    int ret = 0;
+
+    if (!cgroupItem->created && access(cgroupItem->path, F_OK) == 0) {
+        VIR_WARN(_("removing historical cgroup directory: %s"),
+                 cgroupItem->path);
+
+        if (virCgroupRemoveRecursively(cgroupItem->path) != 0) {
+            VIR_WARN(_("failed to remove historical cgroup directory: %s"),
+                     cgroupItem->path);
+        }
+    }
+
+    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;
+        }
+
+        if (cgroupItem->type == VIR_CGROUP_CONTROLLER_CPUSET)
+            virCgroupItemCpusetInherit(cgroupItem);
+
+        if (cgroupItem->type == VIR_CGROUP_CONTROLLER_MEMORY)
+            virCgroupItemSetMemoryUseHierarchy(cgroupItem);
+    }
+
+    return ret;
+}
+
+static int virCgroupItemPath(virCgroupItemPtr cgroupItem,
+                             bool create,
+                             char **path)
+{
+    if (path) {
+        if (virAsprintf(path, "%s", cgroupItem->path) == -1)
+            return -ENOMEM;
+    }
+
+    if (create && virCgroupItemMakePath(cgroupItem) < 0) {
+        if (path)
+            VIR_FREE(*path);
+
+        return -1;
+    }
+
+    return 0;
+}
+
+static int virCgroupItemKeyPath(virCgroupItemPtr cgroupItem,
+                                const char *key,
+                                char **path)
+{
+    int ret = 0;
+    char *cgroupItemPath = NULL;
+
+    ret = virCgroupItemPath(cgroupItem, true, &cgroupItemPath);
+    if (ret < 0)
+        return ret;
+
+    if (virAsprintf(path, "%s/%s", cgroupItemPath, key) == -1)
+        ret = -ENOMEM;
+
+    VIR_FREE(cgroupItemPath);
+    return ret;
+}
+
+int virCgroup2New(const char *name, virCgroup2Ptr parent, virCgroup2Ptr *cgroup)
+{
+    virCgroup2Ptr newCgroup = NULL;
+    virCgroupItemPtr *parentCgroupItems;
+    int ret = -1;
+    int i = 0;
+
+    if (VIR_ALLOC(newCgroup) < 0) {
+        ret = -ENOMEM;
+        goto error;
+    }
+
+    if (!parent) {
+        for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+            if (!rootCgroupItems[i])
+                rootCgroupItems[i] = virCgroupItemRootNew(i);
+            if (!rootCgroupItems[i])
+                goto error;
+            virObjectRef(rootCgroupItems[i]);
+        }
+
+        parentCgroupItems = rootCgroupItems;
+    } else {
+        parentCgroupItems = parent->items;
+    }
+
+    for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+        newCgroup->items[i] = virCgroupItemNew(name, parentCgroupItems[i]);
+        if (!newCgroup->items[i])
+            goto error;
+    }
+
+    *cgroup = newCgroup;
+    newCgroup = NULL;
+    ret = 0;
+
+error:
+    if (!parent) {
+        for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+            if (rootCgroupItems[i])
+                virCgroupItemFree(&rootCgroupItems[i]);
+        }
+    }
+
+    if (newCgroup) {
+        for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+            if (newCgroup->items[i])
+                virCgroupItemFree(&newCgroup->items[i]);
+        }
+        VIR_FREE(newCgroup);
+    }
+
+    return ret;
+}
+
+void virCgroup2Free(virCgroup2Ptr *cgroup)
+{
+    int i;
+
+    if (!cgroup || !*cgroup)
+        return;
+
+    for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
+        virCgroupItemFree(&(*cgroup)->items[i]);
+    }
+
+    VIR_FREE(*cgroup);
+    *cgroup = NULL;
+}
+
 /**
  * virCgroupFree:
  *
@@ -109,6 +552,7 @@ bool virCgroupMounted(virCgroupPtr cgroup, int controller)
 }
 
 #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
+
 /*
  * Process /proc/mounts figuring out what controllers are
  * mounted and where
@@ -134,6 +578,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;
@@ -184,24 +629,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;
@@ -230,6 +675,7 @@ no_memory:
 
 }
 
+
 static int virCgroupDetect(virCgroupPtr group)
 {
     int any = 0;
@@ -315,6 +761,23 @@ int virCgroupPathOfController(virCgroupPtr group,
     return 0;
 }
 
+static int virCgroup2SetValueStr(virCgroup2Ptr group,
+                                 int controller,
+                                 const char *key,
+                                 const char *value)
+{
+    return virCgroupItemSetValueStr(group->items[controller],
+                                    key, value);
+}
+
+static int virCgroup2GetValueStr(virCgroup2Ptr group,
+                                int controller,
+                                const char *key,
+                                char **value)
+{
+    return virCgroupItemGetValueStr(group->items[controller],
+                                    key, value);
+}
 
 static int virCgroupSetValueStr(virCgroupPtr group,
                                 int controller,
@@ -455,7 +918,6 @@ out:
     return rc;
 }
 
-
 #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
 static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group)
 {
@@ -496,6 +958,41 @@ static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group)
     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 virCgroupSetMemoryUseHierarchy(virCgroupPtr group)
 {
     int rc = 0;
@@ -526,6 +1023,38 @@ static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group)
     return rc;
 }
 
+static int virCgroupItemSetMemoryUseHierarchy(virCgroupItemPtr item)
+{
+    int rc = 0;
+    char *value = NULL;
+    const char *filename = "memory.use_hierarchy";
+
+    rc = virCgroupItemGetValueStr(item,
+                                  filename, &value);
+    if (rc != 0) {
+        VIR_ERROR(_("Failed to read %s/%s (%d)"), item->path, filename, rc);
+        return rc;
+    }
+
+    /* Setting twice causes error, so if already enabled, skip setting */
+    if (STREQ(value, "1")) {
+        rc = 0;
+        goto out;
+    }
+
+    VIR_DEBUG("Setting up %s/%s", item->path, filename);
+    rc = virCgroupItemSetValueStr(item,
+                                  filename, "1");
+
+    if (rc != 0) {
+        VIR_ERROR(_("Failed to set %s/%s (%d)"), item->path, filename, rc);
+    }
+
+out:
+    VIR_FREE(value);
+    return rc;
+}
+
 static int virCgroupMakeGroup(virCgroupPtr parent,
                               virCgroupPtr group,
                               bool create,
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index 2ed6ff9..f93c185 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -30,6 +30,10 @@
 struct virCgroup;
 typedef struct virCgroup *virCgroupPtr;
 
+struct virCgroup2;
+typedef struct virCgroup2 virCgroup2;
+typedef virCgroup2 *virCgroup2Ptr;
+
 enum {
     VIR_CGROUP_CONTROLLER_CPU,
     VIR_CGROUP_CONTROLLER_CPUACCT,
@@ -166,4 +170,8 @@ int virCgroupKill(virCgroupPtr group, int signum);
 int virCgroupKillRecursive(virCgroupPtr group, int signum);
 int virCgroupKillPainfully(virCgroupPtr group);
 
+
+int virCgroup2New(const char *name, virCgroup2Ptr parent, virCgroup2Ptr *cgroup);
+void virCgroup2Free(virCgroup2Ptr *cgroup);
+
 #endif /* __VIR_CGROUP_H__ */
-- 
1.8.0.1.240.ge8a1f5a

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]