diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c index 8ebf73eb1f..ed6e74d346 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -31,7 +31,6 @@ #endif /* HAVE_MNTENT_H */ #include -#include "virutil.h" #include "viralloc.h" #include "virfile.h" #include "virt-host-validate-common.h" @@ -39,6 +38,10 @@ #define VIR_FROM_THIS VIR_FROM_NONE +VIR_ENUM_IMPL(virHostValidateCPUFlag, VIR_HOST_VALIDATE_CPU_FLAG_LAST, + "vmx", + "svm"); + static bool quiet; void virHostMsgSetQuiet(bool quietFlag) @@ -188,29 +191,64 @@ int virHostValidateNamespace(const char *hvname, } -bool virHostValidateHasCPUFlag(const char *name) +virBitmapPtr virHostValidateGetCPUFlags(void) { - FILE *fp = fopen("/proc/cpuinfo", "r"); - bool ret = false; + FILE *fp; + virBitmapPtr flags; - if (!fp) - return false; + if (!(fp = fopen("/proc/cpuinfo", "r"))) + return NULL; + + if (!(flags = virBitmapNewQuiet(VIR_HOST_VALIDATE_CPU_FLAG_LAST))) + return NULL; do { char line[1024]; + char *start; + char **tokens; + size_t ntokens; + size_t i; if (!fgets(line, sizeof(line), fp)) break; - if (strstr(line, name)) { - ret = true; - break; + /* The line we're interested in is marked either as "flags" or + * as "Features" depending on the architecture, so check both + * prefixes */ + if (!STRPREFIX(line, "flags") && !STRPREFIX(line, "Features")) + continue; + + /* fgets() includes the trailing newline in the output buffer, + * so we need to clean that up ourselves. We can safely access + * line[strlen(line) - 1] because the checks above would cause + * us to skip empty strings */ + line[strlen(line) - 1] = '\0'; + + /* Skip to the separator */ + if (!(start = strchr(line, ':'))) + continue; + + /* Split the line using " " as a delimiter. The first token + * will always be ":", but that's okay */ + if (!(tokens = virStringSplitCount(start, " ", 0, &ntokens))) + continue; + + /* Go through all flags and check whether one of those we + * might want to check for later on is present; if that's + * the case, set the relevant bit in the bitmap */ + for (i = 0; i < ntokens; i++) { + int value; + + if ((value = virHostValidateCPUFlagTypeFromString(tokens[i])) >= 0) + ignore_value(virBitmapSetBit(flags, value)); } + + virStringFreeListCount(tokens, ntokens); } while (1); VIR_FORCE_FCLOSE(fp); - return ret; + return flags; } @@ -359,15 +397,20 @@ int virHostValidateCGroupController(const char *hvname, int virHostValidateIOMMU(const char *hvname, virHostValidateLevel level) { + virBitmapPtr flags; struct stat sb; const char *bootarg = NULL; bool isAMD = false, isIntel = false; - if (virHostValidateHasCPUFlag("vmx")) + flags = virHostValidateGetCPUFlags(); + + if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_VMX)) isIntel = true; - else if (virHostValidateHasCPUFlag("svm")) + else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SVM)) isAMD = true; + virBitmapFree(flags); + virHostMsgCheck(hvname, "%s", _("for device assignment IOMMU support")); if (isIntel) { diff --git a/tools/virt-host-validate-common.h b/tools/virt-host-validate-common.h index d4c4759b0f..26e006b723 100644 --- a/tools/virt-host-validate-common.h +++ b/tools/virt-host-validate-common.h @@ -23,6 +23,8 @@ # define __VIRT_HOST_VALIDATE_COMMON_H__ # include "internal.h" +# include "virutil.h" +# include "virbitmap.h" typedef enum { VIR_HOST_VALIDATE_FAIL, @@ -32,6 +34,15 @@ typedef enum { VIR_HOST_VALIDATE_LAST, } virHostValidateLevel; +typedef enum { + VIR_HOST_VALIDATE_CPU_FLAG_VMX = 0, + VIR_HOST_VALIDATE_CPU_FLAG_SVM, + + VIR_HOST_VALIDATE_CPU_FLAG_LAST, +} virHostValidateCPUFlag; + +VIR_ENUM_DECL(virHostValidateCPUFlag); + extern void virHostMsgSetQuiet(bool quietFlag); extern void virHostMsgCheck(const char *prefix, @@ -53,7 +64,7 @@ extern int virHostValidateDeviceAccessible(const char *hvname, virHostValidateLevel level, const char *hint); -extern bool virHostValidateHasCPUFlag(const char *name); +extern virBitmapPtr virHostValidateGetCPUFlags(void); extern int virHostValidateLinuxKernel(const char *hvname, int version, diff --git a/tools/virt-host-validate-qemu.c b/tools/virt-host-validate-qemu.c index a9f6c1e1f8..b96b020854 100644 --- a/tools/virt-host-validate-qemu.c +++ b/tools/virt-host-validate-qemu.c @@ -24,14 +24,20 @@ #include "virt-host-validate-qemu.h" #include "virt-host-validate-common.h" +#include "virbitmap.h" int virHostValidateQEMU(void) { + virBitmapPtr flags; int ret = 0; virHostMsgCheck("QEMU", "%s", ("for hardware virtualization")); - if (virHostValidateHasCPUFlag("svm") || - virHostValidateHasCPUFlag("vmx")) { + + flags = virHostValidateGetCPUFlags(); + + if (flags && + (virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SVM) || + virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_VMX))) { virHostMsgPass(); if (virHostValidateDeviceExists("QEMU", "/dev/kvm", VIR_HOST_VALIDATE_FAIL, @@ -48,6 +54,8 @@ int virHostValidateQEMU(void) _("Only emulated CPUs are available, performance will be significantly limited")); } + virBitmapFree(flags); + if (virHostValidateDeviceExists("QEMU", "/dev/vhost-net", VIR_HOST_VALIDATE_WARN, _("Load the 'vhost_net' module to improve performance "