Create field in virDomainDeviceInfo structure to hold file descriptor set the device is associated with. Have the number written into the Device Info XML and parsed from the XML. Remember the next-toy use file descriptor set in the QEMU private domain structure. Upon libvirt restart determine the maximum file descriptor set used in the Device Info XML and remember the next-to-use file descriptor set in the QEMU private domain structure. Upon termination of a domain, reset the next-to-use file descriptor set to its initial value '1'. Stefan Berger --- src/conf/capabilities.h | 5 ++++- src/conf/domain_conf.c | 20 +++++++++++++++++--- src/conf/domain_conf.h | 1 + src/lxc/lxc_domain.c | 3 ++- src/qemu/qemu_domain.c | 23 ++++++++++++++++++++++- src/qemu/qemu_domain.h | 2 ++ src/qemu/qemu_process.c | 2 ++ 7 files changed, 50 insertions(+), 6 deletions(-) Index: libvirt/src/qemu/qemu_domain.c =================================================================== --- libvirt.orig/src/qemu/qemu_domain.c +++ libvirt/src/qemu/qemu_domain.c @@ -219,6 +219,7 @@ static void *qemuDomainObjPrivateAlloc(v goto error; priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX; + priv->nextfdset = 1; return priv; @@ -329,7 +330,25 @@ static int qemuDomainObjPrivateXMLFormat return 0; } -static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data) +static int qemuDomainRebuildFDSet(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED, + virDomainDeviceInfoPtr info, + void *opaque) +{ + int *nextfdset = opaque; + + if (info->fdset > 0 && *nextfdset <= info->fdset) { + *nextfdset = info->fdset + 1; + VIR_DEBUG("Found fdset %u for domain %s. Setting nextfdset = %u", + info->fdset, def->name, *nextfdset); + } + + + return 0; +} + +static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data, + virDomainDefPtr def) { qemuDomainObjPrivatePtr priv = data; char *monitorpath; @@ -471,6 +490,8 @@ static int qemuDomainObjPrivateXMLParse( priv->fakeReboot = virXPathBoolean("boolean(./fakereboot)", ctxt) == 1; + virDomainDeviceInfoIterate(def, qemuDomainRebuildFDSet, &priv->nextfdset); + return 0; error: Index: libvirt/src/qemu/qemu_domain.h =================================================================== --- libvirt.orig/src/qemu/qemu_domain.h +++ libvirt/src/qemu/qemu_domain.h @@ -160,6 +160,8 @@ struct _qemuDomainObjPrivate { qemuDomainCleanupCallback *cleanupCallbacks; size_t ncleanupCallbacks; size_t ncleanupCallbacks_max; + + unsigned int nextfdset; }; struct qemuDomainWatchdogEvent Index: libvirt/src/conf/domain_conf.h =================================================================== --- libvirt.orig/src/conf/domain_conf.h +++ libvirt/src/conf/domain_conf.h @@ -262,6 +262,7 @@ struct _virDomainDeviceInfo { * to consider the new fields */ char *alias; + unsigned int fdset; /* > 0; "-add-fd set=%u,fd=123", fdsetnum */ int type; union { virDevicePCIAddress pci; Index: libvirt/src/conf/domain_conf.c =================================================================== --- libvirt.orig/src/conf/domain_conf.c +++ libvirt/src/conf/domain_conf.c @@ -2219,7 +2219,10 @@ virDomainDeviceInfoFormat(virBufferPtr b if (info->alias && !(flags & VIR_DOMAIN_XML_INACTIVE)) { - virBufferAsprintf(buf, " \n", info->alias); + virBufferAsprintf(buf, " alias); + if (info->fdset > 0) + virBufferAsprintf(buf, " fdset='%u'", info->fdset); + virBufferAddLit(buf, "/>\n"); } if (info->mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) { @@ -2597,6 +2600,7 @@ virDomainDeviceInfoParseXML(xmlNodePtr n xmlNodePtr boot = NULL; xmlNodePtr rom = NULL; char *type = NULL; + char *fdset = NULL; int ret = -1; virDomainDeviceInfoClear(info); @@ -2627,9 +2631,18 @@ virDomainDeviceInfoParseXML(xmlNodePtr n cur = cur->next; } - if (alias) + if (alias) { info->alias = virXMLPropString(alias, "name"); + fdset = virXMLPropString(alias, "fdset"); + if (fdset && virStrToLong_ui(fdset, NULL, 10, &info->fdset) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("incorrect fdset '%s', expecting positive integer"), + fdset); + goto cleanup; + } + } + if (master) { info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB; if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0) @@ -2716,6 +2729,7 @@ cleanup: if (ret == -1) VIR_FREE(info->alias); VIR_FREE(type); + VIR_FREE(fdset); return ret; } @@ -10563,7 +10577,7 @@ static virDomainObjPtr virDomainObjParse VIR_FREE(nodes); if (caps->privateDataXMLParse && - ((caps->privateDataXMLParse)(ctxt, obj->privateData)) < 0) + ((caps->privateDataXMLParse)(ctxt, obj->privateData, obj->def)) < 0) goto error; return obj; Index: libvirt/src/conf/capabilities.h =================================================================== --- libvirt.orig/src/conf/capabilities.h +++ libvirt/src/conf/capabilities.h @@ -149,6 +149,9 @@ struct _virDomainXMLNamespace { virDomainDefNamespaceHref href; }; +typedef struct _virDomainDef virDomainDef; +typedef virDomainDef *virDomainDefPtr; + typedef struct _virCaps virCaps; typedef virCaps* virCapsPtr; struct _virCaps { @@ -164,7 +167,7 @@ struct _virCaps { void *(*privateDataAllocFunc)(void); void (*privateDataFreeFunc)(void *); int (*privateDataXMLFormat)(virBufferPtr, void *); - int (*privateDataXMLParse)(xmlXPathContextPtr, void *); + int (*privateDataXMLParse)(xmlXPathContextPtr, void *, virDomainDefPtr); bool hasWideScsiBus; const char *defaultInitPath; Index: libvirt/src/lxc/lxc_domain.c =================================================================== --- libvirt.orig/src/lxc/lxc_domain.c +++ libvirt/src/lxc/lxc_domain.c @@ -57,7 +57,8 @@ static int virLXCDomainObjPrivateXMLForm return 0; } -static int virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data) +static int virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data, + virDomainDefPtr def ATTRIBUTE_UNUSED) { virLXCDomainObjPrivatePtr priv = data; unsigned long long thepid; Index: libvirt/src/qemu/qemu_process.c =================================================================== --- libvirt.orig/src/qemu/qemu_process.c +++ libvirt/src/qemu/qemu_process.c @@ -4216,6 +4216,8 @@ void qemuProcessStop(virQEMUDriverPtr dr priv->monConfig = NULL; } + priv->nextfdset = 1; + /* shut it off for sure */ ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE| VIR_QEMU_PROCESS_KILL_NOCHECK));