diff --git a/ChangeLog b/ChangeLog index 331ded69e8..e551831caf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Wed Oct 31 10:36:00 CET 2007 Daniel Veillard + + * proxy/libvirt_proxy.c src/proxy_internal.[ch] src/xen_internal.c + src/xen_unified.[ch] src/xend_internal.[ch] src/xml.[ch]: last + patch for the library NUMA support, allow to serialize CPU pinning + to domain configs (but won't work though proxy access), includes + many patches from Saori Fukuta. + Fri Oct 26 21:20:44 EST 2007 Daniel P. Berrange * src/libvirt.c: Don't call state driver API if callback is NULL. diff --git a/proxy/libvirt_proxy.c b/proxy/libvirt_proxy.c index a97b3f9425..d8092a26ee 100644 --- a/proxy/libvirt_proxy.c +++ b/proxy/libvirt_proxy.c @@ -614,7 +614,13 @@ retry2: if (req->len != sizeof(virProxyPacket)) goto comm_error; - xml = xenDaemonDomainDumpXMLByID(conn, request.data.arg, 0); + /* + * Ideally we should get the CPUs used by the domain + * but that information is really node specific and it + * rather hard to get from that code path. So proxy + * users won't see CPU pinning (last NULL arg) + */ + xml = xenDaemonDomainDumpXMLByID(conn, request.data.arg, 0, NULL); if (!xml) { req->data.arg = -1; req->len = sizeof(virProxyPacket); diff --git a/src/proxy_internal.c b/src/proxy_internal.c index aadc018221..385b128810 100644 --- a/src/proxy_internal.c +++ b/src/proxy_internal.c @@ -37,7 +37,6 @@ static int xenProxyListDomains(virConnectPtr conn, int *ids, int maxids); static int xenProxyNumOfDomains(virConnectPtr conn); static unsigned long xenProxyDomainGetMaxMemory(virDomainPtr domain); static int xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info); -static char *xenProxyDomainDumpXML(virDomainPtr domain, int flags); static char *xenProxyDomainGetOSType(virDomainPtr domain); struct xenUnifiedDriver xenProxyDriver = { @@ -69,7 +68,6 @@ struct xenUnifiedDriver xenProxyDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ - xenProxyDomainDumpXML, /* domainDumpXML */ NULL, /* listDefinedDomains */ NULL, /* numOfDefinedDomains */ NULL, /* domainCreate */ @@ -1014,7 +1012,7 @@ xenProxyGetCapabilities (virConnectPtr conn) * * Returns the XML document on success, NULL otherwise. */ -static char * +char * xenProxyDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED) { virProxyPacket req; diff --git a/src/proxy_internal.h b/src/proxy_internal.h index 322d39cdf4..fa8e48abd4 100644 --- a/src/proxy_internal.h +++ b/src/proxy_internal.h @@ -96,6 +96,8 @@ extern virDomainPtr xenProxyLookupByUUID(virConnectPtr conn, extern virDomainPtr xenProxyLookupByName(virConnectPtr conn, const char *domname); +extern char * xenProxyDomainDumpXML(virDomainPtr domain, + int flags); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/xen_internal.c b/src/xen_internal.c index 0bc956e335..3ffac1185f 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -704,7 +704,6 @@ struct xenUnifiedDriver xenHypervisorDriver = { xenHypervisorPinVcpu, /* domainPinVcpu */ xenHypervisorGetVcpus, /* domainGetVcpus */ xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */ - NULL, /* domainDumpXML */ NULL, /* listDefinedDomains */ NULL, /* numOfDefinedDomains */ NULL, /* domainCreate */ diff --git a/src/xen_unified.c b/src/xen_unified.c index 760ec5282f..b4bbd56f1c 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -36,9 +36,16 @@ #include "xend_internal.h" #include "xs_internal.h" #include "xm_internal.h" +#include "xml.h" static int xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info); +static int +xenUnifiedDomainGetMaxVcpus (virDomainPtr dom); +static int +xenUnifiedDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen); /* The five Xen drivers below us. */ static struct xenUnifiedDriver *drivers[XEN_UNIFIED_NR_DRIVERS] = { @@ -113,9 +120,9 @@ int xenNbCells(virConnectPtr conn) { * xenNbCpus: * @conn: pointer to the hypervisor connection * - * Number of NUMa cells present in the actual Node + * Number of CPUs present in the actual Node * - * Returns the number of NUMA cells available on that Node + * Returns the number of CPUs available on that Node */ int xenNbCpus(virConnectPtr conn) { if (nbNodeCpus < 0) @@ -123,6 +130,81 @@ int xenNbCpus(virConnectPtr conn) { return(nbNodeCpus); } +/** + * xenDomainUsedCpus: + * @dom: the domain + * + * Analyze which set of CPUs are used by the domain and + * return a string providing the ranges. + * + * Returns the string which needs to be freed by the caller or + * NULL if the domain uses all CPU or in case of error. + */ +char * +xenDomainUsedCpus(virDomainPtr dom) +{ + char *res = NULL; + int nb_cpu, ncpus; + int nb_vcpu; + char *cpulist = NULL; + unsigned char *cpumap = NULL; + size_t cpumaplen; + int nb = 0; + int n, m; + virVcpuInfoPtr cpuinfo = NULL; + virNodeInfo nodeinfo; + + if (!VIR_IS_CONNECTED_DOMAIN(dom)) + return (NULL); + + nb_cpu = xenNbCpus(dom->conn); + if (nb_cpu <= 0) + return(NULL); + nb_vcpu = xenUnifiedDomainGetMaxVcpus(dom); + if (nb_vcpu <= 0) + return(NULL); + if (xenUnifiedNodeGetInfo(dom->conn, &nodeinfo) < 0) + return(NULL); + + cpulist = (char *) calloc(nb_cpu, sizeof(char)); + if (cpulist == NULL) + goto done; + cpuinfo = malloc(sizeof(virVcpuInfo) * nb_vcpu); + if (cpuinfo == NULL) + goto done; + cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); + cpumap = (unsigned char *) calloc(nb_vcpu, cpumaplen); + if (cpumap == NULL) + goto done; + + if ((ncpus = xenUnifiedDomainGetVcpus(dom, cpuinfo, nb_vcpu, + cpumap, cpumaplen)) >= 0) { + for (n = 0 ; n < ncpus ; n++) { + for (m = 0 ; m < nb_cpu; m++) { + if ((cpulist[m] == 0) && + (VIR_CPU_USABLE(cpumap, cpumaplen, n, m))) { + cpulist[m] = 1; + nb++; + /* if all CPU are used just return NULL */ + if (nb == nb_cpu) + goto done; + + } + } + } + res = virSaveCpuSet(dom->conn, cpulist, nb_cpu); + } + +done: + if (cpulist != NULL) + free(cpulist); + if (cpumap != NULL) + free(cpumap); + if (cpuinfo != NULL) + free(cpuinfo); + return(res); +} + /*----- Dispatch functions. -----*/ /* These dispatch functions follow the model used historically @@ -862,19 +944,24 @@ static char * xenUnifiedDomainDumpXML (virDomainPtr dom, int flags) { GET_PRIVATE(dom->conn); - int i; - char *ret; - for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) - if (priv->opened[i] && drivers[i]->domainDumpXML) { - ret = drivers[i]->domainDumpXML (dom, flags); - if (ret) return ret; + if (dom->id == -1 && priv->xendConfigVersion < 3 ) { + if (priv->opened[XEN_UNIFIED_XM_OFFSET]) + return xenXMDomainDumpXML(dom, flags); + } else { + if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) { + char *cpus, *res; + cpus = xenDomainUsedCpus(dom); + res = xenDaemonDomainDumpXML(dom, flags, cpus); + if (cpus != NULL) + free(cpus); + return(res); } + if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) + return xenProxyDomainDumpXML(dom, flags); + } - /* XXX May need to return an error here if sub-drivers didn't - * set one. We really should change these to direct calls to - * the sub-drivers at a later date. - */ + xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); return NULL; } diff --git a/src/xen_unified.h b/src/xen_unified.h index 86cc1c0ba5..212e826808 100644 --- a/src/xen_unified.h +++ b/src/xen_unified.h @@ -65,7 +65,6 @@ struct xenUnifiedDriver { virDrvDomainPinVcpu domainPinVcpu; virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; - virDrvDomainDumpXML domainDumpXML; virDrvListDefinedDomains listDefinedDomains; virDrvNumOfDefinedDomains numOfDefinedDomains; virDrvDomainCreate domainCreate; @@ -119,6 +118,7 @@ typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr; int xenNbCells(virConnectPtr conn); int xenNbCpus(virConnectPtr conn); +char *xenDomainUsedCpus(virDomainPtr dom); #ifdef __cplusplus } #endif diff --git a/src/xend_internal.c b/src/xend_internal.c index e407a48805..42242d7a54 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -94,7 +94,6 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonDomainPinVcpu, /* domainPinVcpu */ xenDaemonDomainGetVcpus, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ - xenDaemonDomainDumpXML, /* domainDumpXML */ xenDaemonListDefinedDomains, /* listDefinedDomains */ xenDaemonNumOfDefinedDomains, /* numOfDefinedDomains */ xenDaemonDomainCreate, /* domainCreate */ @@ -1343,6 +1342,7 @@ xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf * @root: the root of the parsed S-Expression * @xendConfigVersion: version of xend * @flags: a combination of virDomainXMLFlags + * @cpus: set of cpus the domain may be pinned to * * Parse the xend sexp description and turn it into the XML format similar * to the one unsed for creation. @@ -1352,7 +1352,7 @@ xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf */ static char * xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, - int xendConfigVersion, int flags) + int xendConfigVersion, int flags, const char *cpus) { struct sexpr *cur, *node; const char *tmp; @@ -1438,8 +1438,18 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, if ((cur_mem >= MIN_XEN_GUEST_SIZE) && (cur_mem != max_mem)) virBufferVSprintf(&buf, " %d\n", cur_mem); - virBufferVSprintf(&buf, " %d\n", + + virBufferVSprintf(&buf, " %d\n", sexpr_int(root, "domain/vcpus")); + /* TODO if need to output the cpus values, + * - parse the cpus values if xend exports + * or + * - analyze the cpus values extracted by xenDaemonDomainGetVcpus + */ tmp = sexpr_node(root, "domain/on_poweroff"); if (tmp != NULL) virBufferVSprintf(&buf, " %s\n", tmp); @@ -1802,7 +1812,7 @@ xend_parse_domain_sexp(virConnectPtr conn, char *sexpr, int xendConfigVersion) { if (!root) return NULL; - data = xend_parse_sexp_desc(conn, root, xendConfigVersion, 0); + data = xend_parse_sexp_desc(conn, root, xendConfigVersion, 0, NULL); sexpr_free(root); @@ -2481,7 +2491,8 @@ xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory) dumpxml will work over proxy for inactive domains and this can be removed */ char * -xenDaemonDomainDumpXMLByID(virConnectPtr conn, int domid, int flags) +xenDaemonDomainDumpXMLByID(virConnectPtr conn, int domid, int flags, + const char *cpus) { char *ret = NULL; struct sexpr *root; @@ -2496,14 +2507,16 @@ xenDaemonDomainDumpXMLByID(virConnectPtr conn, int domid, int flags) priv = (xenUnifiedPrivatePtr) conn->privateData; - ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion, flags); + ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion, + flags, cpus); sexpr_free(root); return (ret); } char * -xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags) +xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags, + const char *cpus) { char *ret = NULL; struct sexpr *root; @@ -2518,7 +2531,8 @@ xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags) priv = (xenUnifiedPrivatePtr) conn->privateData; - ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion, flags); + ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion, + flags, cpus); sexpr_free(root); return (ret); @@ -2529,6 +2543,8 @@ xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags) /** * xenDaemonDomainDumpXML: * @domain: a domain object + * @flags: potential dump flags + * @cpus: list of cpu the domain is pinned to. * * Provide an XML description of the domain. * @@ -2536,7 +2552,7 @@ xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags) * the caller must free() the returned value. */ char * -xenDaemonDomainDumpXML(virDomainPtr domain, int flags) +xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus) { xenUnifiedPrivatePtr priv; @@ -2553,9 +2569,11 @@ xenDaemonDomainDumpXML(virDomainPtr domain, int flags) } if (domain->id < 0) - return xenDaemonDomainDumpXMLByName(domain->conn, domain->name, flags); + return xenDaemonDomainDumpXMLByName(domain->conn, domain->name, flags, + cpus); else - return xenDaemonDomainDumpXMLByID(domain->conn, domain->id, flags); + return xenDaemonDomainDumpXMLByID(domain->conn, domain->id, flags, + cpus); } #endif /* !PROXY */ diff --git a/src/xend_internal.h b/src/xend_internal.h index e16d96cc07..fcf42f922f 100644 --- a/src/xend_internal.h +++ b/src/xend_internal.h @@ -110,11 +110,13 @@ int xenDaemonDomainLookupByID(virConnectPtr xend, char *xenDaemonDomainDumpXMLByID(virConnectPtr xend, int domid, - int flags); + int flags, + const char *cpus); char *xenDaemonDomainDumpXMLByName(virConnectPtr xend, const char *name, - int flags); + int flags, + const char *cpus); /** * \brief Lookup information about the host machine @@ -196,7 +198,7 @@ int xenDaemonDomainRestore(virConnectPtr conn, const char *filename); int xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory); int xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory); int xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info); -char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags); +char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus); unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain); char **xenDaemonListDomainsOld(virConnectPtr xend); diff --git a/src/xm_internal.c b/src/xm_internal.c index 288359da09..3dedf73670 100644 --- a/src/xm_internal.c +++ b/src/xm_internal.c @@ -104,7 +104,6 @@ struct xenUnifiedDriver xenXMDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ - xenXMDomainDumpXML, /* domainDumpXML */ xenXMListDefinedDomains, /* listDefinedDomains */ xenXMNumOfDefinedDomains, /* numOfDefinedDomains */ xenXMDomainCreate, /* domainCreate */ @@ -660,11 +659,20 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) { val = MIN_XEN_GUEST_SIZE * 2; virBufferVSprintf(buf, " %ld\n", val * 1024); + virBufferVSprintf(buf, " %ld\n", val); - + virBufferVSprintf(buf, ">%ld\n", val); if (xenXMConfigGetString(conf, "on_poweroff", &str) < 0) str = "destroy"; @@ -1763,6 +1771,7 @@ virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml) { virConfPtr conf = NULL; int hvm = 0, i; xenUnifiedPrivatePtr priv; + char *cpus; doc = xmlReadDoc((const xmlChar *) xml, "domain.xml", NULL, XML_PARSE_NOENT | XML_PARSE_NONET | @@ -1821,6 +1830,32 @@ virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml) { "cannot set vcpus config parameter") < 0) goto error; + cpus = virXPathString("string(/domain/vcpu/@cpuset)", ctxt); + if (cpus != NULL) { + char *ranges; + + ranges = virConvertCpuSet(conn, cpus, 0); + if (ranges != NULL) { + free(cpus); + if (xenXMConfigSetString(conf, "cpus", ranges) < 0) { + free(ranges); + goto error; + } + free(ranges); + } else { + if (xenXMConfigSetString(conf, "cpus", cpus) < 0) { + free(cpus); + goto error; + } + free(cpus); + } + } + + if (xenXMConfigSetStringFromXPath(conn, conf, ctxt, "cpus", /* DV */ + "string(/domain/vcpu/@cpuset)", 1, + "cannot set the cpuset parameter") < 0) + goto error; + obj = xmlXPathEval(BAD_CAST "string(/domain/os/type)", ctxt); if ((obj != NULL) && (obj->type == XPATH_STRING) && (obj->stringval != NULL) && !strcmp((char*)obj->stringval, "hvm")) diff --git a/src/xml.c b/src/xml.c index e87a6e687a..4eca53313e 100644 --- a/src/xml.c +++ b/src/xml.c @@ -135,7 +135,7 @@ parseCpuNumber(const char **str, int maxcpu) } /** - * saveCpuSet: + * virSaveCpuSet: * @conn: connection * @cpuset: pointer to a char array for the CPU set * @maxcpu: number of elements available in @cpuset @@ -145,8 +145,8 @@ parseCpuNumber(const char **str, int maxcpu) * Returns the new string NULL in case of error. The string need to be * freed by the caller. */ -static char * -saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) +char * +virSaveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) { virBufferPtr buf; char *ret; @@ -174,8 +174,6 @@ saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) first = 0; if (cur == start + 1) virBufferVSprintf(buf, "%d", start); - else if (cur == start + 2) - virBufferVSprintf(buf, "%d,%d", start, cur - 1); else virBufferVSprintf(buf, "%d-%d", start, cur - 1); start = -1; @@ -187,8 +185,6 @@ saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) virBufferAdd(buf, ",", -1); if (maxcpu == start + 1) virBufferVSprintf(buf, "%d", start); - else if (maxcpu == start + 2) - virBufferVSprintf(buf, "%d,%d", start, maxcpu - 1); else virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1); } @@ -198,6 +194,7 @@ saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) /** * virParseCpuSet: + * @conn: connection * @str: pointer to a CPU set string pointer * @sep: potential character used to mark the end of string if not 0 * @cpuset: pointer to a char array for the CPU set @@ -300,6 +297,7 @@ virParseCpuSet(virConnectPtr conn, const char **str, char sep, /** * virParseXenCpuTopology: + * @conn: connection * @xml: XML output buffer * @str: the topology string * @maxcpu: number of elements available in @cpuset @@ -362,7 +360,7 @@ virParseXenCpuTopology(virConnectPtr conn, virBufferPtr xml, { char *dump; - dump = saveCpuSet(conn, cpuset, maxcpu); + dump = virSaveCpuSet(conn, cpuset, maxcpu); if (dump != NULL) { virBufferVSprintf(xml, " %s\n", dump); @@ -408,6 +406,45 @@ virParseXenCpuTopology(virConnectPtr conn, virBufferPtr xml, return (-1); } +/** + * virConvertCpuSet: + * @conn: connection + * @str: pointer to a Xen or user provided CPU set string pointer + * @maxcpu: number of CPUs on the node, if 0 4096 will be used + * + * Parse the given CPU set string and convert it to a range based + * string. + * + * Returns a new string which must be freed by the caller or NULL in + * case of error. + */ +char * +virConvertCpuSet(virConnectPtr conn, const char *str, int maxcpu) { + int ret; + char *res, *cpuset; + const char *cur = str; + + if (str == NULL) + return(NULL); + + if (maxcpu <= 0) + maxcpu = 4096; + + cpuset = calloc(maxcpu, sizeof(char)); + if (cpuset == NULL) { + virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0); + return(NULL); + } + + ret = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu); + if (ret < 0) { + free(cpuset); + return(NULL); + } + res = virSaveCpuSet(conn, cpuset, maxcpu); + free(cpuset); + return (res); +} #ifndef PROXY /************************************************************************ @@ -1603,7 +1640,7 @@ virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, if (cpuset != NULL) { res = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu); if (res > 0) { - ranges = saveCpuSet(conn, cpuset, maxcpu); + ranges = virSaveCpuSet(conn, cpuset, maxcpu); if (ranges != NULL) { virBufferVSprintf(&buf, "(cpus '%s')", ranges); free(ranges); diff --git a/src/xml.h b/src/xml.h index ff355ee94b..045ec4e62e 100644 --- a/src/xml.h +++ b/src/xml.h @@ -41,6 +41,12 @@ int virParseCpuSet (virConnectPtr conn, char sep, char *cpuset, int maxcpu); +char * virSaveCpuSet (virConnectPtr conn, + char *cpuset, + int maxcpu); +char * virConvertCpuSet(virConnectPtr conn, + const char *str, + int maxcpu); char * virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name,