[libvirt] [PATCH 15/23] util: Adapt virhostcpu to the new virsysfs

Martin Kletzander mkletzan at redhat.com
Fri Mar 24 19:00:03 UTC 2017


While on that, drop support for kernels from RHEL-5 era (missing
cpu/present file).  Also add some useful functions and export them.

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 src/libvirt_linux.syms    |   1 -
 src/libvirt_private.syms  |   3 +
 src/util/virhostcpu.c     | 345 +++++++++++++---------------------------------
 src/util/virhostcpu.h     |   7 +-
 src/util/virhostcpupriv.h |   2 -
 tests/virhostcputest.c    |   5 +-
 6 files changed, 109 insertions(+), 254 deletions(-)

diff --git a/src/libvirt_linux.syms b/src/libvirt_linux.syms
index a864b78ce7b7..3d66f013062b 100644
--- a/src/libvirt_linux.syms
+++ b/src/libvirt_linux.syms
@@ -5,7 +5,6 @@
 # util/virhostcpu.h
 virHostCPUGetInfoPopulateLinux;
 virHostCPUGetStatsLinux;
-virHostCPUSetSysFSSystemPathLinux;

 # Let emacs know we want case-insensitive sorting
 # Local Variables:
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0a4659fe5e92..c5181e5ff6de 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1712,12 +1712,15 @@ virHookPresent;


 # util/virhostcpu.h
+virHostCPUGetCore;
 virHostCPUGetCount;
 virHostCPUGetInfo;
 virHostCPUGetKVMMaxVCPUs;
 virHostCPUGetMap;
+virHostCPUGetOnline;
 virHostCPUGetOnlineBitmap;
 virHostCPUGetPresentBitmap;
+virHostCPUGetSocket;
 virHostCPUGetStats;
 virHostCPUGetThreadsPerSubcore;
 virHostCPUHasBitmap;
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index f29f3122acee..47f930cdbf3c 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -56,6 +56,7 @@
 #include "virfile.h"
 #include "virtypedparam.h"
 #include "virstring.h"
+#include "virsysfs.h"
 #include "virnuma.h"
 #include "virlog.h"

@@ -189,89 +190,27 @@ virHostCPUGetStatsFreeBSD(int cpuNum,
 #endif /* __FreeBSD__ */

 #ifdef __linux__
-# define SYSFS_SYSTEM_PATH "/sys/devices/system"
 # define CPUINFO_PATH "/proc/cpuinfo"
 # define PROCSTAT_PATH "/proc/stat"
-# define SYSFS_THREAD_SIBLINGS_LIST_LENGTH_MAX 8192
+# define VIR_HOST_CPU_MASK_LEN 1024

 # define LINUX_NB_CPU_STATS 4

-static const char *sysfs_system_path = SYSFS_SYSTEM_PATH;
-
-void virHostCPUSetSysFSSystemPathLinux(const char *path)
-{
-    if (path)
-        sysfs_system_path = path;
-    else
-        sysfs_system_path = SYSFS_SYSTEM_PATH;
-}
-
-/* Return the positive decimal contents of the given
- * DIR/cpu%u/FILE, or -1 on error.  If DEFAULT_VALUE is non-negative
- * and the file could not be found, return that instead of an error;
- * this is useful for machines that cannot hot-unplug cpu0, or where
- * hot-unplugging is disabled, or where the kernel is too old
- * to support NUMA cells, etc.  */
-static int
-virHostCPUGetValue(const char *dir, unsigned int cpu, const char *file,
-                   int default_value)
-{
-    char *path;
-    FILE *pathfp;
-    int value = -1;
-    char value_str[INT_BUFSIZE_BOUND(value)];
-    char *tmp;
-
-    if (virAsprintf(&path, "%s/cpu%u/%s", dir, cpu, file) < 0)
-        return -1;
-
-    pathfp = fopen(path, "r");
-    if (pathfp == NULL) {
-        if (default_value >= 0 && errno == ENOENT)
-            value = default_value;
-        else
-            virReportSystemError(errno, _("cannot open %s"), path);
-        goto cleanup;
-    }
-
-    if (fgets(value_str, sizeof(value_str), pathfp) == NULL) {
-        virReportSystemError(errno, _("cannot read from %s"), path);
-        goto cleanup;
-    }
-    if (virStrToLong_i(value_str, &tmp, 10, &value) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("could not convert '%s' to an integer"),
-                       value_str);
-        goto cleanup;
-    }
-
- cleanup:
-    VIR_FORCE_FCLOSE(pathfp);
-    VIR_FREE(path);
-
-    return value;
-}

 static unsigned long
-virHostCPUCountThreadSiblings(const char *dir, unsigned int cpu)
+virHostCPUCountThreadSiblings(unsigned int cpu)
 {
     unsigned long ret = 0;
-    char *path;
+    int rv = -1;
     char *str = NULL;
     size_t i;

-    if (virAsprintf(&path, "%s/cpu%u/topology/thread_siblings",
-                    dir, cpu) < 0)
-        return 0;
-
-    if (!virFileExists(path)) {
-        /* If file doesn't exist, then pretend our only
-         * sibling is ourself */
+    rv = virSysfsGetCpuValueString(cpu, "topology/thread_siblings", &str);
+    if (rv == -2) {
         ret = 1;
         goto cleanup;
     }
-
-    if (virFileReadAll(path, SYSFS_THREAD_SIBLINGS_LIST_LENGTH_MAX, &str) < 0)
+    if (rv < 0)
         goto cleanup;

     for (i = 0; str[i] != '\0'; i++) {
@@ -281,21 +220,78 @@ virHostCPUCountThreadSiblings(const char *dir, unsigned int cpu)

  cleanup:
     VIR_FREE(str);
-    VIR_FREE(path);
     return ret;
 }

-static int
-virHostCPUParseSocket(const char *dir,
-                   virArch arch,
-                   unsigned int cpu)
+int
+virHostCPUGetSocket(unsigned int cpu, unsigned int *socket)
 {
-    int ret = virHostCPUGetValue(dir, cpu, "topology/physical_package_id", 0);
+    int tmp;
+    int ret = virSysfsGetCpuValueInt(cpu,
+                                     "topology/physical_package_id",
+                                     &tmp);
+
+    /* If the file is not there, it's 0 */
+    if (ret == -2)
+        tmp = 0;
+    else if (ret < 0)
+        return -1;

-    if (ARCH_IS_ARM(arch) || ARCH_IS_PPC(arch) || ARCH_IS_S390(arch)) {
-        /* arm, ppc and s390(x) has -1 */
-        if (ret < 0)
-            ret = 0;
+    /* Some architectures might have '-1' validly in the file, but that actually
+     * means there are no sockets, so from our point of view it's all one socket,
+     * i.e. socket 0.  Similarly when the file does not exist. */
+    if (tmp < 0)
+        tmp = 0;
+
+    *socket = tmp;
+
+    return 0;
+}
+
+int
+virHostCPUGetCore(unsigned int cpu, unsigned int *core)
+{
+    int ret = virSysfsGetCpuValueUint(cpu, "topology/core_id", core);
+
+    /* If the file is not there, it's 0 */
+    if (ret == -2)
+        *core = 0;
+    else if (ret < 0)
+        return -1;
+
+    return 0;
+}
+
+int
+virHostCPUGetOnline(unsigned int cpu, bool *online)
+{
+    unsigned int tmp = 0;
+    int ret = virSysfsGetCpuValueUint(cpu, "online", &tmp);
+
+
+    /* If the file is not there, it's online (doesn't support offlining) */
+    if (ret == -2)
+        tmp = 1;
+    else if (ret < 0)
+        return -1;
+
+    *online = tmp;
+
+    return 0;
+}
+
+virBitmapPtr
+virHostCPUGetSiblingsList(unsigned int cpu)
+{
+    virBitmapPtr ret = NULL;
+    int rv = -1;
+
+    rv = virSysfsGetCpuValueBitmap(cpu, "topology/thread_siblings_list", &ret);
+    if (rv == -2) {
+        /* If the file doesn't exist, the threadis its only sibling */
+        ret = virBitmapNew(cpu + 1);
+        if (ret)
+            ignore_value(virBitmapSetBit(ret, cpu));
     }

     return ret;
@@ -329,9 +325,9 @@ virHostCPUParseNode(const char *node,
     virBitmapPtr sockets_map = NULL;
     virBitmapPtr *cores_maps = NULL;
     int npresent_cpus = virBitmapSize(present_cpus_map);
-    int sock_max = 0;
-    int sock;
-    int core;
+    unsigned int sock_max = 0;
+    unsigned int sock;
+    unsigned int core;
     size_t i;
     int siblings;
     unsigned int cpu;
@@ -366,8 +362,7 @@ virHostCPUParseNode(const char *node,
         if (!virBitmapIsBitSet(online_cpus_map, cpu))
             continue;

-        /* Parse socket */
-        if ((sock = virHostCPUParseSocket(node, arch, cpu)) < 0)
+        if (virHostCPUGetSocket(cpu, &sock) < 0)
             goto cleanup;
         if (sock > ID_MAX) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -421,8 +416,7 @@ virHostCPUParseNode(const char *node,

         processors++;

-        /* Parse socket */
-        if ((sock = virHostCPUParseSocket(node, arch, cpu)) < 0)
+        if (virHostCPUGetSocket(cpu, &sock) < 0)
             goto cleanup;
         if (!virBitmapIsBitSet(sockets_map, sock)) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -435,8 +429,7 @@ virHostCPUParseNode(const char *node,
             /* logical cpu is equivalent to a core on s390 */
             core = cpu;
         } else {
-            if ((core = virHostCPUGetValue(node, cpu,
-                                           "topology/core_id", 0)) < 0)
+            if (virHostCPUGetCore(cpu, &core) < 0)
                 goto cleanup;
         }
         if (core > ID_MAX) {
@@ -449,7 +442,7 @@ virHostCPUParseNode(const char *node,
         if (virBitmapSetBit(cores_maps[sock], core) < 0)
             goto cleanup;

-        if (!(siblings = virHostCPUCountThreadSiblings(node, cpu)))
+        if (!(siblings = virHostCPUCountThreadSiblings(cpu)))
             goto cleanup;

         if (siblings > *threads)
@@ -640,7 +633,7 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
     /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the
      * core, node, socket, thread and topology information from /sys
      */
-    if (virAsprintf(&sysfs_nodedir, "%s/node", sysfs_system_path) < 0)
+    if (virAsprintf(&sysfs_nodedir, "%s/node", virSysfsGetSystemPath()) < 0)
         goto cleanup;

     if (virDirOpenQuiet(&nodedir, sysfs_nodedir) < 0) {
@@ -685,7 +678,7 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
         (*nodes)++;

         if (virAsprintf(&sysfs_cpudir, "%s/node/%s",
-                        sysfs_system_path, nodedirent->d_name) < 0)
+                        virSysfsGetSystemPath(), nodedirent->d_name) < 0)
             goto cleanup;

         if ((nodecpus = virHostCPUParseNode(sysfs_cpudir, arch,
@@ -719,7 +712,7 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
  fallback:
     VIR_FREE(sysfs_cpudir);

-    if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_system_path) < 0)
+    if (virAsprintf(&sysfs_cpudir, "%s/cpu", virSysfsGetSystemPath()) < 0)
         goto cleanup;

     if ((nodecpus = virHostCPUParseNode(sysfs_cpudir, arch,
@@ -857,47 +850,24 @@ virHostCPUGetStatsLinux(FILE *procstat,
 }


-static char *
-virHostCPUGetGlobalPathLinux(const char *file)
-{
-    char *path = NULL;
-
-    if (virAsprintf(&path, "%s/cpu/%s", sysfs_system_path, file) < 0)
-        return NULL;
-
-    return path;
-}
-
-static char *
-virHostCPUGetPresentPathLinux(void)
-{
-    return virHostCPUGetGlobalPathLinux("present");
-}
-
-static char *
-virHostCPUGetOnlinePathLinux(void)
-{
-    return virHostCPUGetGlobalPathLinux("online");
-}
-
 /* Determine the number of CPUs (maximum CPU id + 1) from a file containing
  * a list of CPU ids, like the Linux sysfs cpu/present file */
 static int
-virHostCPUParseCountLinux(const char *path)
+virHostCPUParseCountLinux(void)
 {
     char *str = NULL;
     char *tmp;
     int ret = -1;

-    if (virFileReadAll(path, 5 * VIR_HOST_CPU_MASK_LEN, &str) < 0)
-        goto cleanup;
+    if (virSysfsGetValueString("cpu/present", &str) < 0)
+        return -1;

     tmp = str;
     do {
         if (virStrToLong_i(tmp, &tmp, 10, &ret) < 0 ||
             !strchr(",-\n", *tmp)) {
             virReportError(VIR_ERR_NO_SUPPORT,
-                           _("failed to parse %s"), path);
+                           _("failed to parse %s"), str);
             ret = -1;
             goto cleanup;
         }
@@ -908,32 +878,6 @@ virHostCPUParseCountLinux(const char *path)
     VIR_FREE(str);
     return ret;
 }
-
-/*
- * Linux maintains cpu bit map under cpu/online. For example, if
- * cpuid=5's flag is not set and max cpu is 7, the map file shows
- * 0-4,6-7. This function parses it and returns cpumap.
- */
-static virBitmapPtr
-virHostCPUParseMapLinux(int max_cpuid, const char *path)
-{
-    virBitmapPtr map = NULL;
-    char *str = NULL;
-
-    if (virFileReadAll(path, 5 * VIR_HOST_CPU_MASK_LEN, &str) < 0)
-        goto error;
-
-    if (virBitmapParse(str, &map, max_cpuid) < 0)
-        goto error;
-
-    VIR_FREE(str);
-    return map;
-
- error:
-    VIR_FREE(str);
-    virBitmapFree(map);
-    return NULL;
-}
 #endif


@@ -1063,46 +1007,7 @@ int
 virHostCPUGetCount(void)
 {
 #if defined(__linux__)
-    /* To support older kernels that lack cpu/present, such as 2.6.18
-     * in RHEL5, we fall back to count cpu/cpuNN entries; this assumes
-     * that such kernels also lack hotplug, and therefore cpu/cpuNN
-     * will be consecutive.
-     */
-    char *present_path = NULL;
-    char *cpupath = NULL;
-    int ncpu = -1;
-
-    if (!(present_path = virHostCPUGetPresentPathLinux()))
-        return -1;
-
-    if (virFileExists(present_path)) {
-        ncpu = virHostCPUParseCountLinux(present_path);
-        goto cleanup;
-    }
-
-    if (virAsprintf(&cpupath, "%s/cpu/cpu0", sysfs_system_path) < 0)
-        goto cleanup;
-    if (virFileExists(cpupath)) {
-        ncpu = 0;
-        do {
-            ncpu++;
-            VIR_FREE(cpupath);
-            if (virAsprintf(&cpupath, "%s/cpu/cpu%d",
-                            sysfs_system_path, ncpu) < 0) {
-                ncpu = -1;
-                goto cleanup;
-            }
-        } while (virFileExists(cpupath));
-    } else {
-        /* no cpu/cpu0: we give up */
-        virReportError(VIR_ERR_NO_SUPPORT, "%s",
-                       _("host cpu counting not supported on this node"));
-    }
-
- cleanup:
-    VIR_FREE(present_path);
-    VIR_FREE(cpupath);
-    return ncpu;
+    return virHostCPUParseCountLinux();
 #elif defined(__FreeBSD__) || defined(__APPLE__)
     return virHostCPUGetCountAppleFreeBSD();
 #else
@@ -1126,83 +1031,27 @@ virBitmapPtr
 virHostCPUGetPresentBitmap(void)
 {
 #ifdef __linux__
-    virBitmapPtr present_cpus = NULL;
-    char *present_path = NULL;
-    int npresent_cpus;
-
-    if ((npresent_cpus = virHostCPUGetCount()) < 0)
-        goto cleanup;
-
-    if (!(present_path = virHostCPUGetPresentPathLinux()))
-        goto cleanup;
+    virBitmapPtr ret = NULL;

-    /* If the cpu/present file is available, parse it and exit */
-    if (virFileExists(present_path)) {
-        present_cpus = virHostCPUParseMapLinux(npresent_cpus, present_path);
-        goto cleanup;
-    }
-
-    /* If the file is not available, we can assume that the kernel is
-     * too old to support non-consecutive CPU ids and just mark all
-     * possible CPUs as present */
-    if (!(present_cpus = virBitmapNew(npresent_cpus)))
-        goto cleanup;
-
-    virBitmapSetAll(present_cpus);
-
- cleanup:
-    VIR_FREE(present_path);
+    virSysfsGetValueBitmap("cpu/present", &ret);

-    return present_cpus;
-#endif
+    return ret;
+#else
     virReportError(VIR_ERR_NO_SUPPORT, "%s",
                    _("node present CPU map not implemented on this platform"));
     return NULL;
+#endif
 }

 virBitmapPtr
 virHostCPUGetOnlineBitmap(void)
 {
 #ifdef __linux__
-    char *online_path = NULL;
-    char *cpudir = NULL;
-    virBitmapPtr cpumap;
-    int present;
-
-    present = virHostCPUGetCount();
-    if (present < 0)
-        return NULL;
-
-    if (!(online_path = virHostCPUGetOnlinePathLinux()))
-        return NULL;
-    if (virFileExists(online_path)) {
-        cpumap = virHostCPUParseMapLinux(present, online_path);
-    } else {
-        size_t i;
-
-        cpumap = virBitmapNew(present);
-        if (!cpumap)
-            goto cleanup;
+    virBitmapPtr ret = NULL;

-        if (virAsprintf(&cpudir, "%s/cpu", sysfs_system_path) < 0)
-            goto cleanup;
+    virSysfsGetValueBitmap("cpu/online", &ret);

-        for (i = 0; i < present; i++) {
-            int online = virHostCPUGetValue(cpudir, i, "online", 1);
-            if (online < 0) {
-                virBitmapFree(cpumap);
-                cpumap = NULL;
-                goto cleanup;
-            }
-            if (online)
-                ignore_value(virBitmapSetBit(cpumap, i));
-        }
-    }
-
- cleanup:
-    VIR_FREE(online_path);
-    VIR_FREE(cpudir);
-    return cpumap;
+    return ret;
 #else
     virReportError(VIR_ERR_NO_SUPPORT, "%s",
                    _("node online CPU map not implemented on this platform"));
diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h
index 39f7cf8c8814..a4ce655d6a2e 100644
--- a/src/util/virhostcpu.h
+++ b/src/util/virhostcpu.h
@@ -28,7 +28,6 @@
 # include "virarch.h"
 # include "virbitmap.h"

-# define VIR_HOST_CPU_MASK_LEN 1024

 int virHostCPUGetStats(int cpuNum,
                        virNodeCPUStatsPtr params,
@@ -58,4 +57,10 @@ int virHostCPUStatsAssign(virNodeCPUStatsPtr param,
                           const char *name,
                           unsigned long long value);

+int virHostCPUGetSocket(unsigned int cpu, unsigned int *socket);
+int virHostCPUGetCore(unsigned int cpu, unsigned int *core);
+int virHostCPUGetOnline(unsigned int cpu, bool *online);
+
+virBitmapPtr virHostCPUGetSiblingsList(unsigned int cpu);
+
 #endif /* __VIR_HOSTCPU_H__*/
diff --git a/src/util/virhostcpupriv.h b/src/util/virhostcpupriv.h
index de30983881c2..5e7ae3b88ad3 100644
--- a/src/util/virhostcpupriv.h
+++ b/src/util/virhostcpupriv.h
@@ -25,8 +25,6 @@
 # include "virhostcpu.h"

 # ifdef __linux__
-void virHostCPUSetSysFSSystemPathLinux(const char *path);
-
 int virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
                                    virArch arch,
                                    unsigned int *cpus,
diff --git a/tests/virhostcputest.c b/tests/virhostcputest.c
index 09be1208de40..10e49ea4f0a4 100644
--- a/tests/virhostcputest.c
+++ b/tests/virhostcputest.c
@@ -8,6 +8,7 @@
 #include "testutils.h"
 #include "internal.h"
 #include "virhostcpupriv.h"
+#include "virsysfspriv.h"
 #include "virfile.h"
 #include "virstring.h"

@@ -177,9 +178,9 @@ linuxTestHostCPU(const void *opaque)
         goto cleanup;
     }

-    virHostCPUSetSysFSSystemPathLinux(sysfs_prefix);
+    virSysfsSetSystemPath(sysfs_prefix);
     result = linuxTestCompareFiles(cpuinfo, data->arch, output);
-    virHostCPUSetSysFSSystemPathLinux(NULL);
+    virSysfsSetSystemPath(NULL);

  cleanup:
     VIR_FREE(cpuinfo);
-- 
2.12.0




More information about the libvir-list mailing list