From 91684829be8019f675b847d59d357241d6c0d159 Mon Sep 17 00:00:00 2001 From: Marc Hartmayer Date: Mon, 29 Oct 2018 18:34:58 +0100 Subject: [PATCH] qemu: Introduce caching whether /dev/kvm is accessible MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Introduce caching whether /dev/kvm is usable as the QEMU user:QEMU group. This reduces the overhead of the QEMU capabilities cache lookup. Before this patch there were many fork() calls used for checking whether /dev/kvm is accessible. Now we store the result whether /dev/kvm is accessible or not and we only need to re-run the virFileAccessibleAs check if the ctime of /dev/kvm has changed. Suggested-by: Daniel P. Berrangé Signed-off-by: Marc Hartmayer Signed-off-by: Michal Privoznik --- src/qemu/qemu_capabilities.c | 56 ++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index bf98ff7fcd..51bf97b039 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3264,6 +3264,10 @@ struct _virQEMUCapsCachePriv { virArch hostArch; unsigned int microcodeVersion; char *kernelVersion; + + /* cache whether /dev/kvm is usable as runUid:runGuid */ + virTristateBool kvmUsable; + time_t kvmCtime; }; typedef struct _virQEMUCapsCachePriv virQEMUCapsCachePriv; typedef virQEMUCapsCachePriv *virQEMUCapsCachePrivPtr; @@ -3891,6 +3895,54 @@ virQEMUCapsKVMSupportsNesting(void) } +/* Determine whether '/dev/kvm' is usable as QEMU user:QEMU group. */ +static bool +virQEMUCapsKVMUsable(virQEMUCapsCachePrivPtr priv) +{ + struct stat sb; + static const char *kvm_device = "/dev/kvm"; + virTristateBool value; + virTristateBool cached_value = priv->kvmUsable; + time_t kvm_ctime; + time_t cached_kvm_ctime = priv->kvmCtime; + + if (stat(kvm_device, &sb) < 0) { + if (errno != ENOENT) { + virReportSystemError(errno, + _("Failed to stat %s"), kvm_device); + } + return false; + } + kvm_ctime = sb.st_ctime; + + if (kvm_ctime != cached_kvm_ctime) { + VIR_DEBUG("%s has changed (%lld vs %lld)", kvm_device, + (long long)kvm_ctime, (long long)cached_kvm_ctime); + cached_value = VIR_TRISTATE_BOOL_ABSENT; + } + + if (cached_value != VIR_TRISTATE_BOOL_ABSENT) + return cached_value == VIR_TRISTATE_BOOL_YES; + + if (virFileAccessibleAs(kvm_device, R_OK | W_OK, + priv->runUid, priv->runGid) == 0) { + value = VIR_TRISTATE_BOOL_YES; + } else { + value = VIR_TRISTATE_BOOL_NO; + } + + /* There is a race window between 'stat' and + * 'virFileAccessibleAs'. However, since we're only interested in + * detecting changes *after* the virFileAccessibleAs check, we can + * neglect this here. + */ + priv->kvmCtime = kvm_ctime; + priv->kvmUsable = value; + + return value == VIR_TRISTATE_BOOL_YES; +} + + static bool virQEMUCapsIsValid(void *data, void *privData) @@ -3940,8 +3992,7 @@ virQEMUCapsIsValid(void *data, return true; } - kvmUsable = virFileAccessibleAs("/dev/kvm", R_OK | W_OK, - priv->runUid, priv->runGid) == 0; + kvmUsable = virQEMUCapsKVMUsable(priv); if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) && kvmUsable) { @@ -4763,6 +4814,7 @@ virQEMUCapsCacheNew(const char *libDir, priv->runUid = runUid; priv->runGid = runGid; priv->microcodeVersion = microcodeVersion; + priv->kvmUsable = VIR_TRISTATE_BOOL_ABSENT; if (uname(&uts) == 0 && virAsprintf(&priv->kernelVersion, "%s %s", uts.release, uts.version) < 0) -- 2.47.2