The attached patch is a slimmed down version of a patch
I posted a while back. This expands qemu help message
parsing to look for a kvm version number, which can be
used to determine maximum supported vcpus.
A kvmVersion field is added to the qemu_driver structure,
and a check to determine the version is added to the
libvirtd start up routine. If the kvm version isn't found
(say if kvm isn't installed), kvmVersion is set to 0.
This is against Guido Gunther's patch "maxVCPU runtime
detection": his method takes precendence in the code
if it's available.
Comments welcome.
Thanks,
Cole
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 22a99ec..f79137f 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -418,13 +418,14 @@ virCapsPtr qemudCapsInit(void) {
int qemudExtractVersionInfo(const char *qemu,
unsigned int *retversion,
+ unsigned int *retkvmversion,
unsigned int *retflags) {
const char *const qemuarg[] = { qemu, "-help", NULL };
const char *const qemuenv[] = { "LC_ALL=C", NULL };
pid_t child;
int newstdout = -1;
- int ret = -1, status;
- unsigned int major, minor, micro;
+ int ret = -1, scanret = -1, status;
+ unsigned int major, minor, micro, kvmver;
unsigned int version;
unsigned int flags = 0;
@@ -443,10 +444,12 @@ int qemudExtractVersionInfo(const char *qemu,
if (len < 0)
goto cleanup2;
- if (sscanf(help, "QEMU PC emulator version %u.%u.%u",
- &major, &minor, µ) != 3) {
+ scanret = sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u",
+ &major, &minor, µ, &kvmver);
+ if (scanret == 3)
+ kvmver = 0;
+ else if (scanret != 4)
goto cleanup2;
- }
version = (major * 1000 * 1000) + (minor * 1000) + micro;
@@ -465,6 +468,8 @@ int qemudExtractVersionInfo(const char *qemu,
if (retversion)
*retversion = version;
+ if (retkvmversion)
+ *retkvmversion = kvmver;
if (retflags)
*retflags = flags;
@@ -472,6 +477,7 @@ int qemudExtractVersionInfo(const char *qemu,
qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d",
major, minor, micro, version, flags);
+ qemudDebug("KVM version: %d", kvmver);
cleanup2:
VIR_FREE(help);
@@ -500,28 +506,34 @@ rewait:
return ret;
}
-int qemudExtractVersion(virConnectPtr conn,
- struct qemud_driver *driver) {
+int qemudExtractVersion(struct qemud_driver *driver) {
const char *binary;
struct stat sb;
+ struct utsname ut;
if (driver->qemuVersion > 0)
return 0;
+ uname (&ut);
+
if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
"hvm",
+ ut.machine,
+ "kvm")) == NULL
&&
+ (binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
+ "hvm",
"i686",
"qemu")) == NULL)
return -1;
if (stat(binary, &sb) < 0) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- _("Cannot find QEMU binary %s: %s"), binary,
- strerror(errno));
return -1;
}
- if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
+ if (qemudExtractVersionInfo(binary,
+ &driver->qemuVersion,
+ &driver->kvmVersion,
+ NULL) < 0) {
return -1;
}
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index 88dfade..8d429fb 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -50,6 +50,7 @@ enum qemud_cmd_flags {
/* Main driver state */
struct qemud_driver {
unsigned int qemuVersion;
+ unsigned int kvmVersion;
int nextvmid;
virDomainObjPtr domains;
@@ -83,10 +84,10 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
virCapsPtr qemudCapsInit (void);
-int qemudExtractVersion (virConnectPtr conn,
- struct qemud_driver *driver);
+int qemudExtractVersion (struct qemud_driver *driver);
int qemudExtractVersionInfo (const char *qemu,
unsigned int *version,
+ unsigned int *kvmversion,
unsigned int *flags);
int qemudBuildCommandLine (virConnectPtr conn,
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 0c04da6..d1b9d7c 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -240,6 +240,12 @@ qemudStartup(void) {
if ((qemu_driver->caps = qemudCapsInit()) == NULL)
goto out_of_memory;
+ // Dependent on capabilities being initialized
+ if (qemudExtractVersion(qemu_driver) < 0) {
+ qemudShutdown();
+ return -1;
+ }
+
if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
qemudShutdown();
return -1;
@@ -923,7 +929,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
}
if (qemudExtractVersionInfo(vm->def->emulator,
- NULL,
+ NULL, NULL,
&qemuCmdFlags) < 0) {
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Cannot determine QEMU argv syntax %s"),
@@ -1793,11 +1799,20 @@ static const char *qemudGetType(virConnectPtr conn
ATTRIBUTE_UNUSED) {
}
-static int kvmGetMaxVCPUs(void) {
- int maxvcpus = 1;
+static int kvmGetMaxVCPUs(virConnectPtr conn) {
+
+ struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
+ int maxvcpus = 1, r, fd;
+
+ // KVM-30 added support for up to 4 vcpus
+ // KVM-62 raised this to 16
+ if (driver->kvmVersion < 30)
+ maxvcpus = 1;
+ else if (driver->kvmVersion < 62)
+ maxvcpus = 4;
+ else
+ maxvcpus = 16;
- int r, fd;
-
fd = open(KVM_DEVICE, O_RDONLY);
if (fd < 0) {
qemudLog(QEMUD_WARN, _("Unable to open " KVM_DEVICE ":
%s\n"), strerror(errno));
@@ -1820,10 +1835,8 @@ static int qemudGetMaxVCPUs(virConnectPtr conn, const char *type)
{
if (STRCASEEQ(type, "qemu"))
return 16;
- /* XXX future KVM will support SMP. Need to probe
- kernel to figure out KVM module version i guess */
if (STRCASEEQ(type, "kvm"))
- return kvmGetMaxVCPUs();
+ return kvmGetMaxVCPUs(conn);
if (STRCASEEQ(type, "kqemu"))
return 1;
@@ -1993,7 +2006,7 @@ static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
- if (qemudExtractVersion(conn, driver) < 0)
+ if (qemudExtractVersion(driver) < 0)
return -1;
*version = qemu_driver->qemuVersion;
@@ -3035,7 +3048,7 @@ static int qemudDomainChangeEjectableMedia(virDomainPtr dom,
}
if (qemudExtractVersionInfo(vm->def->emulator,
- NULL,
+ NULL, NULL,
&qemuCmdFlags) < 0) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
_("Cannot determine QEMU argv syntax %s"),