[Libvir] [PATCH] finish NUMA code reorg, plug cpuset at creat time support

Daniel Veillard veillard at redhat.com
Tue Oct 30 20:54:36 UTC 2007


On Thu, Oct 25, 2007 at 05:25:25PM +0900, Saori Fukuta wrote:
> On Wed, 24 Oct 2007 05:12:42 -0400 Daniel Veillard wrote:
> > To extract the cpuset
> > you need to call the existing functionalities we have for the vcpu 
> > affinities (and this may be a bit costly).
> > 
> > > Then, I could not get the cpus values by sexpr_node(root, "domain/cpus").
> > > 
> > > I guess this is a bug of Xen, and this has not been fixed with latest
> > > upstream Xen. So I will work about this for Xen before discussing about
> > > how xend exports.
> > 
> >   It was never in xen and I think teh new way being based on Xen-API you
> > won't get a fix for upstream for our case here. I would not expect a fix
> > to xend to get the solution but work it out in libvirt, but you can try ...
> 
> I reconsidered about it and I agreed with you, because we won't get 
> the cpus values when pined several PCPU to each VCPU, like the 
> following case:
>    domA  VCPU:0  PCPU:0-1
>          VCPU:1  PCPU:0-1
>          VCPU:2  PCPU:2
>          VCPU:3  PCPU:3
> And, we certainly can get the vcpu affinities above by other way 
> (i.e. call "xenDaemonDomainGetVcpus" and analyze the result), but
> it will be costly at this time, though I would like to make them.
> So could you commit the patch first to support the cpus value 
> at starting/defining the guest domain for RHEL5.2 ? 
> 
> Please let me know if you have any comments and suggestions.

  Okay sorry it took so long, I got distrated by something else and 
I wanted to come back with a more complete patch for the following:
  - make sure that cpu expressions coming from the user are reparsed
    and translated to ranges to make sure we don't have a mismatch between
    the external representations and what is accepted both by libvirt
    and xend
  - Saving the pinning in the XML makes things really complex.
    alls the XML dump routines of xend assume an SExpr input but 
    the affinity is not available there. Querying xend may be very costly
    and it way better to ask at the xen_unified level where the hypervisor
    hypercall will be used if available
  - as a result I removed the DumpXML entry point from xen_unified because
    you need to extend parameters in the xend case
  - also when coming from the proxy you just have the domain id and
    it's harder to get the cpu list in an efficient way without 
    messing even more with the code

I still think CPU affinity in the domain is misplaced, but well, okay
I agree to do this for real cpus, this complicates the code a bit though.

  The associated patch compiles, but I have not yet tested it, it's 
basically how I would expect to finish the NUMA work, but it certainly need
debug and testing. I will look at this tomorrow, but I welcome feedback :-)

Daniel

-- 
Red Hat Virtualization group http://redhat.com/virtualization/
Daniel Veillard      | virtualization library  http://libvirt.org/
veillard at redhat.com  | libxml GNOME XML XSLT toolkit  http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine  http://rpmfind.net/
-------------- next part --------------
Index: proxy/libvirt_proxy.c
===================================================================
RCS file: /data/cvs/libxen/proxy/libvirt_proxy.c,v
retrieving revision 1.19
diff -u -p -r1.19 libvirt_proxy.c
--- proxy/libvirt_proxy.c	30 Sep 2007 13:09:07 -0000	1.19
+++ proxy/libvirt_proxy.c	30 Oct 2007 20:42:29 -0000
@@ -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);
Index: src/proxy_internal.c
===================================================================
RCS file: /data/cvs/libxen/src/proxy_internal.c,v
retrieving revision 1.34
diff -u -p -r1.34 proxy_internal.c
--- src/proxy_internal.c	14 Aug 2007 12:29:41 -0000	1.34
+++ src/proxy_internal.c	30 Oct 2007 20:42:29 -0000
@@ -37,7 +37,6 @@ static int xenProxyListDomains(virConnec
 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 c
  *
  * Returns the XML document on success, NULL otherwise. 
  */
-static char *
+char *
 xenProxyDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
 {
     virProxyPacket req;
Index: src/proxy_internal.h
===================================================================
RCS file: /data/cvs/libxen/src/proxy_internal.h,v
retrieving revision 1.9
diff -u -p -r1.9 proxy_internal.h
--- src/proxy_internal.h	6 Jul 2007 15:11:22 -0000	1.9
+++ src/proxy_internal.h	30 Oct 2007 20:42:29 -0000
@@ -96,6 +96,8 @@ extern virDomainPtr xenProxyLookupByUUID
 extern virDomainPtr xenProxyLookupByName(virConnectPtr conn,
                                          const char *domname);
 
+extern char *       xenProxyDomainDumpXML(virDomainPtr domain,
+					  int flags);
 #ifdef __cplusplus
 }
 #endif                          /* __cplusplus */
Index: src/xen_internal.c
===================================================================
RCS file: /data/cvs/libxen/src/xen_internal.c,v
retrieving revision 1.97
diff -u -p -r1.97 xen_internal.c
--- src/xen_internal.c	22 Oct 2007 20:28:55 -0000	1.97
+++ src/xen_internal.c	30 Oct 2007 20:42:29 -0000
@@ -704,7 +704,6 @@ struct xenUnifiedDriver xenHypervisorDri
     xenHypervisorPinVcpu, /* domainPinVcpu */
     xenHypervisorGetVcpus, /* domainGetVcpus */
     xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */
-    NULL, /* domainDumpXML */
     NULL, /* listDefinedDomains */
     NULL, /* numOfDefinedDomains */
     NULL, /* domainCreate */
Index: src/xen_unified.c
===================================================================
RCS file: /data/cvs/libxen/src/xen_unified.c,v
retrieving revision 1.25
diff -u -p -r1.25 xen_unified.c
--- src/xen_unified.c	22 Oct 2007 20:28:55 -0000	1.25
+++ src/xen_unified.c	30 Oct 2007 20:42:29 -0000
@@ -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,19 @@ 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 (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+        char *cpus;
 
-    /* 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.
-     */
+	cpus = xenDomainUsedCpus(dom);
+        return xenDaemonDomainDumpXML(dom, flags, cpus);
+    }
+    if (priv->opened[XEN_UNIFIED_PROXY_OFFSET])
+        return xenProxyDomainDumpXML(dom, flags);
+    if (priv->opened[XEN_UNIFIED_XM_OFFSET])
+        return xenXMDomainDumpXML(dom, flags);
+
+    xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return NULL;
 }
 
Index: src/xen_unified.h
===================================================================
RCS file: /data/cvs/libxen/src/xen_unified.h,v
retrieving revision 1.6
diff -u -p -r1.6 xen_unified.h
--- src/xen_unified.h	22 Oct 2007 20:28:55 -0000	1.6
+++ src/xen_unified.h	30 Oct 2007 20:42:29 -0000
@@ -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 *xenUn
 
 int xenNbCells(virConnectPtr conn);
 int xenNbCpus(virConnectPtr conn);
+char *xenDomainUsedCpus(virDomainPtr dom);
 #ifdef __cplusplus
 }
 #endif
Index: src/xend_internal.c
===================================================================
RCS file: /data/cvs/libxen/src/xend_internal.c,v
retrieving revision 1.151
diff -u -p -r1.151 xend_internal.c
--- src/xend_internal.c	22 Oct 2007 20:28:55 -0000	1.151
+++ src/xend_internal.c	30 Oct 2007 20:42:29 -0000
@@ -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 xe
  * @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 xe
  */
 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,
     if ((cur_mem >= MIN_XEN_GUEST_SIZE) && (cur_mem != max_mem))
 	virBufferVSprintf(&buf, "  <currentMemory>%d</currentMemory>\n",
 	                  cur_mem);
-    virBufferVSprintf(&buf, "  <vcpu>%d</vcpu>\n",
+    
+    virBufferVSprintf(&buf, "  <vcpu");
+    if (cpus != NULL) {
+	virBufferVSprintf(&buf, " cpuset='%s'", cpus);
+    }
+    virBufferVSprintf(&buf, ">%d</vcpu>\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, "  <on_poweroff>%s</on_poweroff>\n", tmp);
@@ -1802,7 +1812,7 @@ xend_parse_domain_sexp(virConnectPtr con
   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 do
    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
 
     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(virConnectP
 
     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(virConnectP
 /**
  * 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(virConnectP
  *         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 doma
     }
 
     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 */
 
Index: src/xend_internal.h
===================================================================
RCS file: /data/cvs/libxen/src/xend_internal.h,v
retrieving revision 1.34
diff -u -p -r1.34 xend_internal.h
--- src/xend_internal.h	30 Sep 2007 13:09:07 -0000	1.34
+++ src/xend_internal.h	30 Oct 2007 20:42:29 -0000
@@ -110,11 +110,13 @@ int xenDaemonDomainLookupByID(virConnect
 
 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
 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);
 
Index: src/xm_internal.c
===================================================================
RCS file: /data/cvs/libxen/src/xm_internal.c,v
retrieving revision 1.41
diff -u -p -r1.41 xm_internal.c
--- src/xm_internal.c	10 Oct 2007 17:55:38 -0000	1.41
+++ src/xm_internal.c	30 Oct 2007 20:42:29 -0000
@@ -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
             val = MIN_XEN_GUEST_SIZE * 2;
     virBufferVSprintf(buf, "  <memory>%ld</memory>\n", val * 1024);
 
-
+    virBufferVSprintf(buf, "  <vcpu"); /* DV */
+    if (xenXMConfigGetString(conf, "cpus", &str) == 0) {
+        char *ranges;
+
+	ranges = virConvertCpuSet(conn, str, 0);
+	if (ranges != NULL) {
+	    virBufferVSprintf(buf, " cpuset='%s'", ranges);
+	    free(ranges);
+	} else
+	    virBufferVSprintf(buf, " cpuset='%s'", str);
+    }
     if (xenXMConfigGetInt(conf, "vcpus", &val) < 0)
         val = 1;
-    virBufferVSprintf(buf, "  <vcpu>%ld</vcpu>\n", val);
-
+    virBufferVSprintf(buf, ">%ld</vcpu>\n", val);
 
     if (xenXMConfigGetString(conf, "on_poweroff", &str) < 0)
         str = "destroy";
@@ -1763,6 +1771,7 @@ virConfPtr xenXMParseXMLToConfig(virConn
     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(virConn
                                    "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"))
Index: src/xml.c
===================================================================
RCS file: /data/cvs/libxen/src/xml.c,v
retrieving revision 1.96
diff -u -p -r1.96 xml.c
--- src/xml.c	26 Oct 2007 13:41:18 -0000	1.96
+++ src/xml.c	30 Oct 2007 20:42:30 -0000
@@ -135,7 +135,7 @@ parseCpuNumber(const char **str, int max
 }
 
 /**
- * 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 max
  * 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;
@@ -198,6 +198,7 @@ saveCpuSet(virConnectPtr conn, char *cpu
 
 /**
  * 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 +301,7 @@ virParseCpuSet(virConnectPtr conn, const
 
 /**
  * virParseXenCpuTopology:
+ * @conn: connection
  * @xml: XML output buffer
  * @str: the topology string 
  * @maxcpu: number of elements available in @cpuset
@@ -362,7 +364,7 @@ virParseXenCpuTopology(virConnectPtr con
         {
             char *dump;
 
-            dump = saveCpuSet(conn, cpuset, maxcpu);
+            dump = virSaveCpuSet(conn, cpuset, maxcpu);
             if (dump != NULL) {
                 virBufferVSprintf(xml, "           <dump>%s</dump>\n",
                                   dump);
@@ -408,6 +410,45 @@ virParseXenCpuTopology(virConnectPtr con
     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, ret);
+    free(cpuset);
+    return (res);
+}
 #ifndef PROXY
 
 /************************************************************************
@@ -1603,7 +1644,7 @@ virDomainParseXMLDesc(virConnectPtr conn
             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);
Index: src/xml.h
===================================================================
RCS file: /data/cvs/libxen/src/xml.h,v
retrieving revision 1.19
diff -u -p -r1.19 xml.h
--- src/xml.h	22 Oct 2007 20:28:55 -0000	1.19
+++ src/xml.h	30 Oct 2007 20:42:30 -0000
@@ -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,


More information about the libvir-list mailing list