mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 18:41:17 +00:00
* src/xend_internal.c: update to cpuset parsing code for NUMA
Daniel
This commit is contained in:
parent
d620b00ffa
commit
a87420ae59
@ -1,3 +1,7 @@
|
|||||||
|
Mon Oct 22 15:05:30 CEST 2007 Daniel Veillard <veillard@redhat.com>
|
||||||
|
|
||||||
|
* src/xend_internal.c: update to cpuset parsing code for NUMA
|
||||||
|
|
||||||
Fri Oct 19 17:08:08 CEST 2007 Daniel Veillard <veillard@redhat.com>
|
Fri Oct 19 17:08:08 CEST 2007 Daniel Veillard <veillard@redhat.com>
|
||||||
|
|
||||||
* src/Makefile.am: fix tst build rule
|
* src/Makefile.am: fix tst build rule
|
||||||
|
@ -1896,24 +1896,349 @@ sexpr_to_xend_node_info(struct sexpr *root, virNodeInfoPtr info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getNumber:
|
* skipSpaces:
|
||||||
* @pointer: pointer to string beginning with numerical characters
|
* @str: pointer to the char pointer used
|
||||||
* @result: pointer to integer for storing the numerical result
|
|
||||||
*
|
*
|
||||||
* Internal routine extracting a number from the beginning of a string
|
* Skip potential blanks, this includes space tabs, line feed,
|
||||||
|
* carriage returns and also '\\' which can be erronously emitted
|
||||||
|
* by xend
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
skipSpaces(const char **str) {
|
||||||
|
const char *cur = *str;
|
||||||
|
|
||||||
|
while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
|
||||||
|
(*cur == '\r') || (*cur == '\\')) cur++;
|
||||||
|
*str = cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseNumber:
|
||||||
|
* @str: pointer to the char pointer used
|
||||||
*
|
*
|
||||||
* Returns the number of characters that were extracted as digits
|
* Parse a number
|
||||||
* or -1 if no digits were found.
|
*
|
||||||
|
* Returns the CPU number or -1 in case of error. @str will be
|
||||||
|
* updated to skip the number.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
getNumber (const char * pointer, int * result) {
|
parseNumber(const char **str) {
|
||||||
int len = 0;
|
int ret = 0;
|
||||||
while (isdigit(*(pointer + len)))
|
const char *cur = *str;
|
||||||
len++;
|
|
||||||
if (len == 0)
|
if ((*cur < '0') || (*cur > '9'))
|
||||||
return -1;
|
return(-1);
|
||||||
*(result) = atoi(pointer);
|
|
||||||
return (len);
|
while ((*cur >= '0') && (*cur <= '9')) {
|
||||||
|
ret = ret * 10 + (*cur - '0');
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
*str = cur;
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseCpuNumber:
|
||||||
|
* @str: pointer to the char pointer used
|
||||||
|
* @maxcpu: maximum CPU number allowed
|
||||||
|
*
|
||||||
|
* Parse a CPU number
|
||||||
|
*
|
||||||
|
* Returns the CPU number or -1 in case of error. @str will be
|
||||||
|
* updated to skip the number.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parseCpuNumber(const char **str, int maxcpu) {
|
||||||
|
int ret = 0;
|
||||||
|
const char *cur = *str;
|
||||||
|
|
||||||
|
if ((*cur < '0') || (*cur > '9'))
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
while ((*cur >= '0') && (*cur <= '9')) {
|
||||||
|
ret = ret * 10 + (*cur - '0');
|
||||||
|
if (ret > maxcpu)
|
||||||
|
return(-1);
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
*str = cur;
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 /* Not used yet */
|
||||||
|
/**
|
||||||
|
* saveCpuSet:
|
||||||
|
* @conn: connection
|
||||||
|
* @cpuset: pointer to a char array for the CPU set
|
||||||
|
* @maxcpu: number of elements available in @cpuset
|
||||||
|
*
|
||||||
|
* Serialize the cpuset to a string
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
virBufferPtr buf;
|
||||||
|
char *ret;
|
||||||
|
int start, cur;
|
||||||
|
int first = 1;
|
||||||
|
|
||||||
|
if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000))
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
buf = virBufferNew(1000);
|
||||||
|
if (buf == NULL) {
|
||||||
|
virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"));
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
cur = 0;
|
||||||
|
start = -1;
|
||||||
|
while (cur < maxcpu) {
|
||||||
|
if (cpuset[cur]) {
|
||||||
|
if (start == -1)
|
||||||
|
start = cur;
|
||||||
|
} else if (start != -1) {
|
||||||
|
if (!first)
|
||||||
|
virBufferAdd(buf, ",", -1);
|
||||||
|
else
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
if (start != -1) {
|
||||||
|
if (!first)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
ret = virBufferContentAndFree(buf);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseCpuSet:
|
||||||
|
* @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
|
||||||
|
* @maxcpu: number of elements available in @cpuset
|
||||||
|
*
|
||||||
|
* Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
|
||||||
|
* to 1, and 0 otherwise. The syntax allows coma separated entries each
|
||||||
|
* can be either a CPU number, ^N to unset that CPU or N-M for ranges.
|
||||||
|
*
|
||||||
|
* Returns the number of CPU found in that set, or -1 in case of error.
|
||||||
|
* @cpuset is modified accordingly to the value parsed.
|
||||||
|
* @str is updated to the end of the part parsed
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parseCpuSet(virConnectPtr conn, const char **str, char sep, char *cpuset,
|
||||||
|
int maxcpu)
|
||||||
|
{
|
||||||
|
const char *cur;
|
||||||
|
int ret = 0;
|
||||||
|
int i, start, last;
|
||||||
|
int neg = 0;
|
||||||
|
|
||||||
|
if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000))
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
cur = *str;
|
||||||
|
skipSpaces(&cur);
|
||||||
|
if (*cur == 0)
|
||||||
|
goto parse_error;
|
||||||
|
|
||||||
|
/* initialize cpumap to all 0s */
|
||||||
|
for (i = 0;i < maxcpu;i++)
|
||||||
|
cpuset[i] = 0;
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
while ((*cur != 0) && (*cur != sep)) {
|
||||||
|
/*
|
||||||
|
* 3 constructs are allowed:
|
||||||
|
* - N : a single CPU number
|
||||||
|
* - N-M : a range of CPU numbers with N < M
|
||||||
|
* - ^N : remove a single CPU number from the current set
|
||||||
|
*/
|
||||||
|
if (*cur == '^') {
|
||||||
|
cur++;
|
||||||
|
neg = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*cur < '0') || (*cur > '9'))
|
||||||
|
goto parse_error;
|
||||||
|
start = parseCpuNumber(&cur, maxcpu);
|
||||||
|
if (start < 0)
|
||||||
|
goto parse_error;
|
||||||
|
skipSpaces(&cur);
|
||||||
|
if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
|
||||||
|
if (neg) {
|
||||||
|
if (cpuset[start] == 1) {
|
||||||
|
cpuset[start] = 0;
|
||||||
|
ret--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cpuset[start] == 0) {
|
||||||
|
cpuset[start] = 1;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (*cur == '-') {
|
||||||
|
if (neg)
|
||||||
|
goto parse_error;
|
||||||
|
cur++;
|
||||||
|
skipSpaces(&cur);
|
||||||
|
last = parseCpuNumber(&cur, maxcpu);
|
||||||
|
if (last < start)
|
||||||
|
goto parse_error;
|
||||||
|
for (i = start;i <= last;i++) {
|
||||||
|
if (cpuset[i] == 0) {
|
||||||
|
cpuset[i] = 1;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skipSpaces(&cur);
|
||||||
|
}
|
||||||
|
if (*cur == ',') {
|
||||||
|
cur++;
|
||||||
|
skipSpaces(&cur);
|
||||||
|
neg = 0;
|
||||||
|
} else if ((*cur == 0) || (*cur == sep)) {
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
goto parse_error;
|
||||||
|
}
|
||||||
|
*str = cur;
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
parse_error:
|
||||||
|
virXendError(conn, VIR_ERR_XEN_CALL,
|
||||||
|
_("topology cpuset syntax error"));
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseXenCpuTopology:
|
||||||
|
* @xml: XML output buffer
|
||||||
|
* @str: the topology string
|
||||||
|
* @maxcpu: number of elements available in @cpuset
|
||||||
|
*
|
||||||
|
* Parse a Xend CPU topology string and build the associated XML
|
||||||
|
* format.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, -1 in case of error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parseTopology(virConnectPtr conn, virBufferPtr xml, const char *str,
|
||||||
|
int maxcpu)
|
||||||
|
{
|
||||||
|
const char *cur;
|
||||||
|
char *cpuset = NULL;
|
||||||
|
int cell, cpu, nb_cpus;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu >100000))
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
cpuset = malloc(maxcpu * sizeof(char));
|
||||||
|
if (cpuset == NULL)
|
||||||
|
goto memory_error;
|
||||||
|
|
||||||
|
cur = str;
|
||||||
|
while (*cur != 0) {
|
||||||
|
/*
|
||||||
|
* Find the next NUMA cell described in the xend output
|
||||||
|
*/
|
||||||
|
cur = strstr(cur, "node");
|
||||||
|
if (cur == NULL)
|
||||||
|
break;
|
||||||
|
cur += 4;
|
||||||
|
cell = parseNumber(&cur);
|
||||||
|
if (cell < 0)
|
||||||
|
goto parse_error;
|
||||||
|
skipSpaces(&cur);
|
||||||
|
if (*cur != ':')
|
||||||
|
goto parse_error;
|
||||||
|
cur++;
|
||||||
|
skipSpaces(&cur);
|
||||||
|
if (!strncmp (cur, "no cpus", 7)) {
|
||||||
|
nb_cpus = 0;
|
||||||
|
for (cpu = 0;cpu < maxcpu;cpu++)
|
||||||
|
cpuset[cpu] = 0;
|
||||||
|
} else {
|
||||||
|
nb_cpus = parseCpuSet(conn, &cur, 'n', cpuset, maxcpu);
|
||||||
|
if (nb_cpus < 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add xml for all cpus associated with that cell
|
||||||
|
*/
|
||||||
|
ret = virBufferVSprintf (xml, "\
|
||||||
|
<cell id='%d'>\n\
|
||||||
|
<cpus num='%d'>\n", cell, nb_cpus);
|
||||||
|
#ifdef STANDALONE
|
||||||
|
{
|
||||||
|
char *dump;
|
||||||
|
|
||||||
|
dump = saveCpuSet(conn, cpuset, maxcpu);
|
||||||
|
if (dump != NULL) {
|
||||||
|
virBufferVSprintf (xml, " <dump>%s</dump>\n", dump);
|
||||||
|
free(dump);
|
||||||
|
} else {
|
||||||
|
virBufferVSprintf (xml, " <error>%s</error>\n",
|
||||||
|
"Failed to dump CPU set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ret < 0)
|
||||||
|
goto memory_error;
|
||||||
|
for (cpu = 0;cpu < maxcpu;cpu++) {
|
||||||
|
if (cpuset[cpu] == 1) {
|
||||||
|
ret = virBufferVSprintf (xml, "\
|
||||||
|
<cpu id='%d'/>\n", cpu);
|
||||||
|
if (ret < 0)
|
||||||
|
goto memory_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = virBufferAdd (xml, "\
|
||||||
|
</cpus>\n\
|
||||||
|
</cell>\n", -1);
|
||||||
|
if (ret < 0)
|
||||||
|
goto memory_error;
|
||||||
|
|
||||||
|
}
|
||||||
|
free(cpuset);
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
parse_error:
|
||||||
|
virXendError(conn, VIR_ERR_XEN_CALL,
|
||||||
|
_("topology syntax error"));
|
||||||
|
error:
|
||||||
|
if (cpuset != NULL)
|
||||||
|
free(cpuset);
|
||||||
|
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
memory_error:
|
||||||
|
if (cpuset != NULL)
|
||||||
|
free(cpuset);
|
||||||
|
virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"));
|
||||||
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1929,21 +2254,9 @@ static int
|
|||||||
sexpr_to_xend_topology_xml(virConnectPtr conn, struct sexpr *root, virBufferPtr xml)
|
sexpr_to_xend_topology_xml(virConnectPtr conn, struct sexpr *root, virBufferPtr xml)
|
||||||
{
|
{
|
||||||
const char *nodeToCpu;
|
const char *nodeToCpu;
|
||||||
const char *offset;
|
|
||||||
int cellNum;
|
|
||||||
int numCells = 0;
|
int numCells = 0;
|
||||||
int numCpus;
|
int numCpus;
|
||||||
int cellCpuCount = 0;
|
|
||||||
int nodeCpuCount = 0;
|
|
||||||
int start;
|
|
||||||
int finish;
|
|
||||||
int r;
|
int r;
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
int cpuNum;
|
|
||||||
int *cpuIdsPtr = NULL;
|
|
||||||
int *iCpuIdsPtr = NULL;
|
|
||||||
char next;
|
|
||||||
|
|
||||||
nodeToCpu = sexpr_node(root, "node/node_to_cpu");
|
nodeToCpu = sexpr_node(root, "node/node_to_cpu");
|
||||||
if (nodeToCpu == NULL) {
|
if (nodeToCpu == NULL) {
|
||||||
@ -1955,134 +2268,21 @@ sexpr_to_xend_topology_xml(virConnectPtr conn, struct sexpr *root, virBufferPtr
|
|||||||
numCells = sexpr_int(root, "node/nr_nodes");
|
numCells = sexpr_int(root, "node/nr_nodes");
|
||||||
numCpus = sexpr_int(root, "node/nr_cpus");
|
numCpus = sexpr_int(root, "node/nr_cpus");
|
||||||
|
|
||||||
/* array for holding all cpu numbers associated with a single cell.
|
|
||||||
* Should never need more than numCpus (which is total number of
|
|
||||||
* cpus for the node)
|
|
||||||
*/
|
|
||||||
cpuIdsPtr = iCpuIdsPtr = malloc(numCpus * sizeof(int));
|
|
||||||
if (cpuIdsPtr == NULL) {
|
|
||||||
goto vir_buffer_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start filling in xml */
|
/* start filling in xml */
|
||||||
r = virBufferVSprintf (xml,
|
r = virBufferVSprintf (xml,
|
||||||
"\
|
"\
|
||||||
<topology>\n\
|
<topology>\n\
|
||||||
<cells num='%d'>\n",
|
<cells num='%d'>\n",
|
||||||
numCells);
|
numCells);
|
||||||
if (r == -1) goto vir_buffer_failed;
|
if (r < 0) goto vir_buffer_failed;
|
||||||
|
|
||||||
offset = nodeToCpu;
|
r = parseTopology(conn, xml, nodeToCpu, numCpus);
|
||||||
/* now iterate through all cells and find associated cpu ids */
|
if (r < 0) goto error;
|
||||||
/* example of string being parsed: "node0:0-3,7,9-10\n node1:11-14\n" */
|
|
||||||
while ((offset = strstr(offset, "node")) != NULL) {
|
|
||||||
cpuIdsPtr = iCpuIdsPtr;
|
|
||||||
cellCpuCount = 0;
|
|
||||||
offset +=4;
|
|
||||||
if ((len = getNumber(offset, &cellNum)) < 0) {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
offset += len;
|
|
||||||
if (*(offset) != ':') {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
offset++;
|
|
||||||
/* get list of cpus associated w/ single cell */
|
|
||||||
while (1) {
|
|
||||||
len = getNumber(offset, &cpuNum);
|
|
||||||
if (len < 0) {
|
|
||||||
if (!strncmp (offset, "no cpus", 7)){
|
|
||||||
*(cpuIdsPtr++) = -1;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL, "topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset += len;
|
|
||||||
next = *(offset);
|
|
||||||
if (next == '-') {
|
|
||||||
offset++;
|
|
||||||
start = cpuNum;
|
|
||||||
if ((len = getNumber(offset, &finish)) < 0) {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (start > finish) {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL, " topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
}
|
|
||||||
for (i=start; i<=finish; i++) {
|
|
||||||
nodeCpuCount++;
|
|
||||||
if (nodeCpuCount > numCpus) {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL,
|
|
||||||
"conflicting cpu counts");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
*(cpuIdsPtr++) = i;
|
|
||||||
cellCpuCount++;
|
|
||||||
}
|
|
||||||
offset += len;
|
|
||||||
next = *(offset);
|
|
||||||
offset++;
|
|
||||||
if (next == ',') {
|
|
||||||
continue;
|
|
||||||
} else if ((next == '\\') || (next =='\0')) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL,
|
|
||||||
" topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* add the single number */
|
|
||||||
if (nodeCpuCount >= numCpus) {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL,
|
|
||||||
"conflicting cpu counts");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
*(cpuIdsPtr++) = cpuNum;
|
|
||||||
cellCpuCount++;
|
|
||||||
nodeCpuCount++;
|
|
||||||
if (next == ',') {
|
|
||||||
offset++;
|
|
||||||
continue;
|
|
||||||
} else if ((next == '\\') || (next =='\0')) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
virXendError(conn, VIR_ERR_XEN_CALL,
|
|
||||||
" topology string syntax error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add xml for all cpus associated with one cell */
|
|
||||||
r = virBufferVSprintf (xml, "\
|
|
||||||
<cell id='%d'>\n\
|
|
||||||
<cpus num='%d'>\n", cellNum, cellCpuCount);
|
|
||||||
if (r == -1) goto vir_buffer_failed;
|
|
||||||
|
|
||||||
for (i = 0; i < cellCpuCount; i++) {
|
|
||||||
if (*(iCpuIdsPtr + i) == -1)
|
|
||||||
break;
|
|
||||||
r = virBufferVSprintf (xml, "\
|
|
||||||
<cpu id='%d'/>\n", *(iCpuIdsPtr + i));
|
|
||||||
if (r == -1) goto vir_buffer_failed;
|
|
||||||
}
|
|
||||||
r = virBufferAdd (xml, "\
|
|
||||||
</cpus>\n\
|
|
||||||
</cell>\n", -1);
|
|
||||||
if (r == -1) goto vir_buffer_failed;
|
|
||||||
}
|
|
||||||
r = virBufferAdd (xml, "\
|
r = virBufferAdd (xml, "\
|
||||||
</cells>\n\
|
</cells>\n\
|
||||||
</topology>\n", -1);
|
</topology>\n", -1);
|
||||||
if (r == -1) goto vir_buffer_failed;
|
if (r < 0) goto vir_buffer_failed;
|
||||||
free(iCpuIdsPtr);
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
|
|
||||||
@ -2090,8 +2290,6 @@ vir_buffer_failed:
|
|||||||
virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate new buffer"));
|
virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate new buffer"));
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (iCpuIdsPtr)
|
|
||||||
free(iCpuIdsPtr);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user