[libvirt] [PATCH 0/2] Fix two problems with creating new storage volumes
by Laine Stump
Both of these problems can occur only if a new storage volume is
created by copying it from an existing volume. The first is a problem
if the new volume is longer than the old (the new volume won't be
zero-filled at the end), and the second happens if the new and old
volumes are the same length (fsync wouldn't be called at the end of
writing the new volume) (actually, before the 1st fix is applied, that
problem would exist for *all* new volumes created as copies of
existing volumes).
14 years, 4 months
[libvirt] [PATCH] Fix a deadlock in bi-directional p2p concurrent migration.
by Chris Lalancette
If you try to execute two concurrent migrations p2p
from A->B and B->A, the two libvirtd's will deadlock
trying to perform the migrations. The reason for this is
that in p2p migration, the libvirtd's are responsible for
making the RPC Prepare, Migrate, and Finish calls. However,
they are currently holding the driver lock while doing so,
which basically guarantees deadlock in this scenario.
This patch fixes the situation by adding
qemuDomainObjEnterRemoteWithDriver and
qemuDomainObjExitRemoteWithDriver helper methods. The Enter
take an additional object reference, then drops both the
domain object lock and the driver lock. The Exit takes
both the driver and domain object lock, then drops the
reference. Adding calls to these Enter and Exit helpers
around remote calls in the various migration methods
seems to fix the problem for me in testing.
This should make the situation safe. The additional domain
object reference ensures that the domain object won't disappear
while this operation is happening. The BeginJob that is called
inside of qemudDomainMigratePerform ensures that we can't execute a
second migrate (or shutdown, or save, etc) job while the
migration is active. Finally, the additional check on the state
of the vm after we reacquire the locks ensures that we can't
be surprised by an external event (domain crash, etc).
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/qemu/qemu_driver.c | 57 ++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5f2607c..1eff4bc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -531,6 +531,21 @@ static void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, virD
}
}
+static void qemuDomainObjEnterRemoteWithDriver(struct qemud_driver *driver,
+ virDomainObjPtr obj)
+{
+ virDomainObjRef(obj);
+ virDomainObjUnlock(obj);
+ qemuDriverUnlock(driver);
+}
+
+static void qemuDomainObjExitRemoteWithDriver(struct qemud_driver *driver,
+ virDomainObjPtr obj)
+{
+ qemuDriverLock(driver);
+ virDomainObjLock(obj);
+ virDomainObjUnref(obj);
+}
static int qemuCgroupControllerActive(struct qemud_driver *driver,
int controller)
@@ -10753,14 +10768,25 @@ static int doTunnelMigrate(virDomainPtr dom,
/* virStreamNew only fails on OOM, and it reports the error itself */
goto cleanup;
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
internalret = dconn->driver->domainMigratePrepareTunnel(dconn, st,
flags, dname,
resource, dom_xml);
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
if (internalret < 0)
/* domainMigratePrepareTunnel sets the error for us */
goto cleanup;
+ /* the domain may have shutdown or crashed while we had the locks dropped
+ * in qemuDomainObjEnterRemoteWithDriver, so check again
+ */
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto cleanup;
+ }
+
/* 3. start migration on source */
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (flags & VIR_MIGRATE_NON_SHARED_DISK)
@@ -10833,8 +10859,10 @@ cancel:
finish:
dname = dname ? dname : dom->name;
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
ddomain = dconn->driver->domainMigrateFinish2
(dconn, dname, NULL, 0, uri, flags, retval);
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
cleanup:
if (client_sock != -1)
@@ -10873,19 +10901,32 @@ static int doNonTunnelMigrate(virDomainPtr dom,
virDomainPtr ddomain = NULL;
int retval = -1;
char *uri_out = NULL;
+ int rc;
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
/* NB we don't pass 'uri' into this, since that's the libvirtd
* URI in this context - so we let dest pick it */
- if (dconn->driver->domainMigratePrepare2(dconn,
- NULL, /* cookie */
- 0, /* cookielen */
- NULL, /* uri */
- &uri_out,
- flags, dname,
- resource, dom_xml) < 0)
+ rc = dconn->driver->domainMigratePrepare2(dconn,
+ NULL, /* cookie */
+ 0, /* cookielen */
+ NULL, /* uri */
+ &uri_out,
+ flags, dname,
+ resource, dom_xml);
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
+ if (rc < 0)
/* domainMigratePrepare2 sets the error for us */
goto cleanup;
+ /* the domain may have shutdown or crashed while we had the locks dropped
+ * in qemuDomainObjEnterRemoteWithDriver, so check again
+ */
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto cleanup;
+ }
+
if (uri_out == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("domainMigratePrepare2 did not set uri"));
@@ -10899,8 +10940,10 @@ static int doNonTunnelMigrate(virDomainPtr dom,
finish:
dname = dname ? dname : dom->name;
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
ddomain = dconn->driver->domainMigrateFinish2
(dconn, dname, NULL, 0, uri_out, flags, retval);
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
if (ddomain)
virUnrefDomain(ddomain);
--
1.7.1.1
14 years, 4 months
[libvirt] [PATCH] Make virsh setmaxmem balloon only when successful.
by Chris Lalancette
After playing around with virsh setmaxmem for a bit,
I ran into some surprising behavior; if a hypervisor does
not support the virDomainSetMaxMemory() API, but the value
specified for setmaxmem is less than the current amount
of memory in the domain, the domain would be ballooned
down *before* an error was reported.
To make this more consistent, run virDomainSetMaxMemory()
before trying to shrink; that way, if an error is thrown,
no changes to the running domain are made.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
tools/virsh.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 0631590..97bfa20 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2529,19 +2529,19 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
return FALSE;
}
+ if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
+ vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
+ virDomainFree(dom);
+ return FALSE;
+ }
+
if (kilobytes < info.memory) {
if (virDomainSetMemory(dom, kilobytes) != 0) {
- virDomainFree(dom);
vshError(ctl, "%s", _("Unable to shrink current MemorySize"));
- return FALSE;
+ ret = FALSE;
}
}
- if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
- vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
- ret = FALSE;
- }
-
virDomainFree(dom);
return ret;
}
--
1.6.6.1
14 years, 4 months
[libvirt] [PATCH] Use unsigned long in cmdSetmem.
by Chris Lalancette
The virsh command "setmem" takes as input a number that
should represent an unsigned long number of kilobytes. Fix
cmdSetmem to properly parse this as an unsigned long instead
of an int.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
tools/virsh.c | 30 ++++++++++++++++++++++++++----
1 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 551e97b..63816dc 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -223,6 +223,8 @@ static int vshCmddefHelp(vshControl *ctl, const char *name);
static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found);
+static unsigned long vshCommandOptUL(const vshCmd *cmd, const char *name,
+ int *found);
static char *vshCommandOptString(const vshCmd *cmd, const char *name,
int *found);
static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name,
@@ -2534,7 +2536,7 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom;
virDomainInfo info;
- int kilobytes;
+ unsigned long kilobytes;
int ret = TRUE;
if (!vshConnectionUsability(ctl, ctl->conn))
@@ -2543,10 +2545,10 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- kilobytes = vshCommandOptInt(cmd, "kilobytes", &kilobytes);
+ kilobytes = vshCommandOptUL(cmd, "kilobytes", NULL);
if (kilobytes <= 0) {
virDomainFree(dom);
- vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
+ vshError(ctl, _("Invalid value of %lu for memory size"), kilobytes);
return FALSE;
}
@@ -2558,7 +2560,7 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
if (kilobytes > info.maxMem) {
virDomainFree(dom);
- vshError(ctl, _("Requested memory size %d kb is larger than maximum of %lu kb"),
+ vshError(ctl, _("Requested memory size %lu kb is larger than maximum of %lu kb"),
kilobytes, info.maxMem);
return FALSE;
}
@@ -9628,6 +9630,26 @@ vshCommandOptInt(const vshCmd *cmd, const char *name, int *found)
return res;
}
+static unsigned long
+vshCommandOptUL(const vshCmd *cmd, const char *name, int *found)
+{
+ vshCmdOpt *arg = vshCommandOpt(cmd, name);
+ unsigned long res = 0;
+ int num_found = FALSE;
+ char *end_p = NULL;
+
+ if ((arg != NULL) && (arg->data != NULL)) {
+ res = strtoul(arg->data, &end_p, 10);
+ if ((arg->data == end_p) || (*end_p!= 0))
+ num_found = FALSE;
+ else
+ num_found = TRUE;
+ }
+ if (found)
+ *found = num_found;
+ return res;
+}
+
/*
* Returns option as STRING
*/
--
1.7.1.1
14 years, 4 months
[libvirt] Libvirt segmentation fault on non root user
by Vasco Silva
Dear all,
Im trying to connet to libvirtd on my local machine, but i only can contact
as root user.
When i run virsh command as root user, all works as expected:
[root@localhost libvirt]# virsh list
Id Name State
----------------------------------
When i try to run virsh as user, i get the following errors:
[user@localhost ~]$ virsh list
error: unable to connect to '@/home/user/.libvirt/libvirt-sock', libvirtd
may need to be started: Connection refused
error: failed to connect to the hypervisor
on /var/log/messages, i found a segmentation fault:
Jul 20 02:46:00 localhost kernel: libvirtd[22177]: segfault at 28 ip
0000000000496ca7 sp 00007f72a328bdf8 error 4 in libvirtd[400000+cc000]
on my /etc/libvirt/libvirtd.conf, i have uncommented these 3 entries:
listen_tls = 0
listen_tcp = 1
auth_tcp = "none"
my system:
Linux localhost 2.6.33.5-desktop-2xcm #1 SMP Tue Jun 22 15:53:23 WEST 2010
x86_64 x86_64 x86_64 GNU/Linux - Mandriva Free 2010
libvirt-utils-0.8.0-2mdv2010.1
I don't know how to resolve this segmentation fault, and what is the cause.
Any help will be appreciated.
Thanks,
Vasco Silva
14 years, 4 months
[libvirt] A problem about live migration of kvm
by 姚远
>From qemu-kvm-0.12.1, kvm has the function about live migration with
non-shared storage. But I don't know how to use it. In the qemu monitor,
"migrate -d tcp:10.1.10.42:444" which is based on shared storage is going
well. I don't know how to use the command of "-b or -i" or maybe I don't
know the correct format of uri.
the source and destination system is Fedora-13, and the version of kvm is
qemu-kvm-0.12.3.
When I use the "migrate -d -b tcp:10.1.10.42:4444", the qemu monitor don't
show nothing. When I use "info migrate",there shows "migrate status:
failed". I don't know why? I hope someone who used this command successfully
would help me, thank you.
14 years, 4 months
[libvirt] ChangeLog-old file: do we need it?
by Justin Clift
Hi us,
We have an old ChangeLog file in the base directory that seems to just
be hanging around and not really serving a useful purpose. And takes up
space.
Can we remove it?
Regards and best wishes,
Justin Clift
14 years, 4 months
[libvirt] How to use live migration of kvm with non-shared storage
by 姚远
>From qemu-kvm-0.12.1, kvm has the function about live migration with
non-shared storage. But I don't know how to use it. In the qemu monitor,
"migrate -d tcp:10.1.10.42:444" which is based on shared storage is going
well. I don't know how to use the command of "-b or -i" or maybe I don't
know the correct format of uri.
the source and destination system is Fedora-13, and the version of kvm is
qemu-kvm-0.12.3.
When I use the "migrate -d -b tcp:10.1.10.42:4444", the qemu monitor don't
show nothing. When I use "info migrate",there shows "migrate status:
failed". I don't know why? I hope someone who used this command successfully
would help me, thank you
14 years, 4 months
[libvirt] [PATCH] cpu: Add support for CPU vendor
by Jiri Denemark
By specifying <vendor> element in CPU requirements a guest can be
restricted to run only on CPUs by a given vendor. Host CPU vendor is
also specified in capabilities XML.
The vendor is checked when migrating a guest but it's not forced, i.e.,
a guest configured without <vendor> element can be freely migrated.
---
Sorry for such a big patch but the bulk of it is in cpu/ which is not so easy
to be splitted reasonably.
docs/formatcaps.html.in | 1 +
docs/formatdomain.html.in | 8 +
docs/schemas/capability.rng | 5 +
docs/schemas/domain.rng | 7 +
src/conf/cpu_conf.c | 14 ++
src/conf/cpu_conf.h | 1 +
src/cpu/cpu.c | 9 +-
src/cpu/cpu.h | 6 +-
src/cpu/cpu_map.c | 36 ++++--
src/cpu/cpu_map.h | 20 ++-
src/cpu/cpu_map.xml | 6 +
src/cpu/cpu_x86.c | 307 +++++++++++++++++++++++++++++++++++++++++--
tests/testutilsqemu.c | 1 +
13 files changed, 389 insertions(+), 32 deletions(-)
diff --git a/docs/formatcaps.html.in b/docs/formatcaps.html.in
index 525a331..dcbf35a 100644
--- a/docs/formatcaps.html.in
+++ b/docs/formatcaps.html.in
@@ -22,6 +22,7 @@ BIOS you will see</p>
<vmx/>
</features>
<model>core2duo</model>
+ <vendor>Intel</vendor>
<topology sockets="1" cores="2" threads="1"/>
<feature name="lahf_lm"/>
<feature name='xtpr'/>
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 425a1e4..8f0cf3b 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -220,6 +220,7 @@
...
<cpu match='exact'>
<model>core2duo</model>
+ <vendor>Intel</vendor>
<topology sockets='1' cores='2' threads='1'/>
<feature policy='disable' name='lahf_lm'/>
</cpu>
@@ -267,6 +268,13 @@
definition can be found in <code>cpu_map.xml</code> file installed
in libvirt's data directory.</dd>
+ <dt><code>vendor</code></dt>
+ <dd><span class="since">Since 0.8.2</span> the content of the
+ <code>vendor</code> element specifies CPU vendor requested by the
+ guest. If this element is missing, the guest can be run on a CPU
+ matching given features regardless on its vendor. The list of
+ supported vendors can be found in <code>cpu_map.xml</code>.</dd>
+
<dt><code>topology</code></dt>
<dd>The <code>topology</code> element specifies requested topology of
virtual CPU provided to the guest. Three non-zero values have to be
diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng
index 67e8cf2..f894b09 100644
--- a/docs/schemas/capability.rng
+++ b/docs/schemas/capability.rng
@@ -79,6 +79,11 @@
<element name='model'>
<text/>
</element>
+ <optional>
+ <element name='vendor'>
+ <text/>
+ </element>
+ </optional>
<element name='topology'>
<attribute name='sockets'>
<ref name='positiveInteger'/>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index fd57917..1d56f5b 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -1557,6 +1557,7 @@
<interleave>
<ref name="cpuModel"/>
<optional>
+ <ref name="cpuVendor"/>
<ref name="cpuTopology"/>
</optional>
<zeroOrMore>
@@ -1584,6 +1585,12 @@
</element>
</define>
+ <define name="cpuVendor">
+ <element name="vendor">
+ <text/>
+ </element>
+ </define>
+
<define name="cpuFeature">
<element name="feature">
<attribute name="policy">
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index c51ac4e..d9aa69c 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -58,6 +58,7 @@ virCPUDefFree(virCPUDefPtr def)
VIR_FREE(def->model);
VIR_FREE(def->arch);
+ VIR_FREE(def->vendor);
for (i = 0 ; i < def->nfeatures ; i++)
VIR_FREE(def->features[i].name);
@@ -79,6 +80,7 @@ virCPUDefCopy(const virCPUDefPtr cpu)
if (VIR_ALLOC(copy) < 0
|| (cpu->arch && !(copy->arch = strdup(cpu->arch)))
|| (cpu->model && !(copy->model = strdup(cpu->model)))
+ || (cpu->vendor && !(copy->vendor = strdup(cpu->vendor)))
|| VIR_ALLOC_N(copy->features, cpu->nfeatures) < 0)
goto no_memory;
@@ -173,6 +175,13 @@ virCPUDefParseXML(const xmlNodePtr node,
goto error;
}
+ def->vendor = virXPathString("string(./vendor[1])", ctxt);
+ if (def->vendor && !def->model) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("CPU vendor specified without CPU model"));
+ goto error;
+ }
+
if (virXPathNode("./topology[1]", ctxt)) {
int ret;
unsigned long ul;
@@ -349,6 +358,11 @@ virCPUDefFormatBuf(virBufferPtr buf,
if (def->model)
virBufferVSprintf(buf, "%s <model>%s</model>\n", indent, def->model);
+ if (def->vendor) {
+ virBufferVSprintf(buf, "%s <vendor>%s</vendor>\n",
+ indent, def->vendor);
+ }
+
if (def->sockets && def->cores && def->threads) {
virBufferVSprintf(buf, "%s <topology", indent);
virBufferVSprintf(buf, " sockets='%u'", def->sockets);
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index a30991d..1c29192 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -72,6 +72,7 @@ struct _virCPUDef {
int match; /* enum virCPUMatch */
char *arch;
char *model;
+ char *vendor;
unsigned int sockets;
unsigned int cores;
unsigned int threads;
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 8d6c22b..279eee7 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -173,14 +173,15 @@ cpuEncode(const char *arch,
union cpuData **required,
union cpuData **optional,
union cpuData **disabled,
- union cpuData **forbidden)
+ union cpuData **forbidden,
+ union cpuData **vendor)
{
struct cpuArchDriver *driver;
VIR_DEBUG("arch=%s, cpu=%p, forced=%p, required=%p, "
- "optional=%p, disabled=%p, forbidden=%p",
+ "optional=%p, disabled=%p, forbidden=%p, vendor=%p",
NULLSTR(arch), cpu, forced, required,
- optional, disabled, forbidden);
+ optional, disabled, forbidden, vendor);
if ((driver = cpuGetSubDriver(arch)) == NULL)
return -1;
@@ -193,7 +194,7 @@ cpuEncode(const char *arch,
}
return driver->encode(cpu, forced, required,
- optional, disabled, forbidden);
+ optional, disabled, forbidden, vendor);
}
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index 40f2a7d..a745917 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -58,7 +58,8 @@ typedef int
union cpuData **required,
union cpuData **optional,
union cpuData **disabled,
- union cpuData **forbidden);
+ union cpuData **forbidden,
+ union cpuData **vendor);
typedef void
(*cpuArchDataFree) (union cpuData *data);
@@ -119,7 +120,8 @@ cpuEncode (const char *arch,
union cpuData **required,
union cpuData **optional,
union cpuData **disabled,
- union cpuData **forbidden);
+ union cpuData **forbidden,
+ union cpuData **vendor);
extern void
cpuDataFree (const char *arch,
diff --git a/src/cpu/cpu_map.c b/src/cpu/cpu_map.c
index 5fb88e0..263bb9e 100644
--- a/src/cpu/cpu_map.c
+++ b/src/cpu/cpu_map.c
@@ -32,9 +32,14 @@
#define CPUMAPFILE PKGDATADIR "/cpu_map.xml"
+VIR_ENUM_IMPL(cpuMapElement, CPU_MAP_ELEMENT_LAST,
+ "vendor",
+ "feature",
+ "model")
+
static int load(xmlXPathContextPtr ctxt,
- const char *node,
+ enum cpuMapElement element,
cpuMapLoadCallback callback,
void *data)
{
@@ -47,9 +52,10 @@ static int load(xmlXPathContextPtr ctxt,
cur = ctxt_node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST node)) {
+ xmlStrEqual(cur->name,
+ BAD_CAST cpuMapElementTypeToString(element))) {
ctxt->node = cur;
- if (callback(ctxt, data) < 0)
+ if (callback(element, ctxt, data) < 0)
goto cleanup;
}
@@ -66,16 +72,15 @@ cleanup:
int cpuMapLoad(const char *arch,
- cpuMapLoadCallback feature_cb,
- void *model_data,
- cpuMapLoadCallback model_cb,
- void *feature_data)
+ cpuMapLoadCallback cb,
+ void *data)
{
xmlDocPtr xml = NULL;
xmlXPathContextPtr ctxt = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *xpath = NULL;
int ret = -1;
+ int element;
if (arch == NULL) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
@@ -83,6 +88,12 @@ int cpuMapLoad(const char *arch,
return -1;
}
+ if (cb == NULL) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no callback provided"));
+ return -1;
+ }
+
if ((xml = xmlParseFile(CPUMAPFILE)) == NULL) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse CPU map file: %s"),
@@ -107,11 +118,12 @@ int cpuMapLoad(const char *arch,
goto cleanup;
}
- if ((feature_cb && load(ctxt, "feature", feature_cb, feature_data) < 0) ||
- (model_cb && load(ctxt, "model", model_cb, model_data) < 0)) {
- virCPUReportError(VIR_ERR_INTERNAL_ERROR,
- _("cannot parse CPU map for %s architecture"), arch);
- goto cleanup;
+ for (element = 0; element < CPU_MAP_ELEMENT_LAST; element++) {
+ if (load(ctxt, element, cb, data) < 0) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse CPU map for %s architecture"), arch);
+ goto cleanup;
+ }
}
ret = 0;
diff --git a/src/cpu/cpu_map.h b/src/cpu/cpu_map.h
index 3d72c7f..e26c7c1 100644
--- a/src/cpu/cpu_map.h
+++ b/src/cpu/cpu_map.h
@@ -27,15 +27,25 @@
# include "xml.h"
+enum cpuMapElement {
+ CPU_MAP_ELEMENT_VENDOR,
+ CPU_MAP_ELEMENT_FEATURE,
+ CPU_MAP_ELEMENT_MODEL,
+
+ CPU_MAP_ELEMENT_LAST
+};
+
+VIR_ENUM_DECL(cpuMapElement)
+
+
typedef int
-(*cpuMapLoadCallback) (xmlXPathContextPtr ctxt,
+(*cpuMapLoadCallback) (enum cpuMapElement element,
+ xmlXPathContextPtr ctxt,
void *data);
extern int
cpuMapLoad(const char *arch,
- cpuMapLoadCallback feature_cb,
- void *model_data,
- cpuMapLoadCallback model_cb,
- void *feature_data);
+ cpuMapLoadCallback cb,
+ void *data);
#endif /* __VIR_CPU_MAP_H__ */
diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
index 084b879..3ec4a7e 100644
--- a/src/cpu/cpu_map.xml
+++ b/src/cpu/cpu_map.xml
@@ -1,5 +1,9 @@
<cpus>
<arch name='x86'>
+ <!-- vendor definitions -->
+ <vendor name='Intel' string='GenuineIntel'/>
+ <vendor name='AMD' string='AuthenticAMD'/>
+
<!-- standard features, EDX -->
<feature name='fpu'> <!-- CPUID_FP87 -->
<cpuid function='0x00000001' edx='0x00000001'/>
@@ -310,6 +314,7 @@
<model name='phenom'>
<model name='pentiumpro'/>
+ <vendor name='AMD'/>
<feature name='mtrr'/>
<feature name='clflush'/>
<feature name='mca'/>
@@ -328,6 +333,7 @@
<model name='athlon'>
<model name='pentiumpro'/>
+ <vendor name='AMD'/>
<feature name='pse36'/>
<feature name='vme'/>
<feature name='mtrr'/>
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 0266ce9..114235c 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -35,8 +35,18 @@
#define VIR_FROM_THIS VIR_FROM_CPU
+#define VENDOR_STRING_LENGTH 12
+
+
static const char *archs[] = { "i686", "x86_64" };
+struct x86_vendor {
+ char *name;
+ struct cpuX86cpuid cpuid;
+
+ struct x86_vendor *next;
+};
+
struct x86_feature {
char *name;
unsigned int ncpuid;
@@ -47,6 +57,7 @@ struct x86_feature {
struct x86_model {
char *name;
+ const struct x86_vendor *vendor;
unsigned int ncpuid;
struct cpuX86cpuid *cpuid;
@@ -54,6 +65,7 @@ struct x86_model {
};
struct x86_map {
+ struct x86_vendor *vendors;
struct x86_feature *features;
struct x86_model *models;
};
@@ -212,6 +224,44 @@ x86DataCopy(const union cpuData *data)
}
+static int
+x86DataAddCpuid(union cpuData *data,
+ const struct cpuX86cpuid *cpuid)
+{
+ struct cpuX86cpuid **cpuids;
+ int *len;
+ unsigned int pos;
+ unsigned int ext;
+
+ if (cpuid->function < CPUX86_EXTENDED) {
+ pos = cpuid->function;
+ ext = 0;
+ len = &data->x86.basic_len;
+ cpuids = &data->x86.basic;
+ } else {
+ pos = cpuid->function - CPUX86_EXTENDED;
+ ext = CPUX86_EXTENDED;
+ len = &data->x86.extended_len;
+ cpuids = &data->x86.extended;
+ }
+
+ if (pos >= *len) {
+ unsigned int i;
+
+ if (VIR_ALLOC_N(*cpuids, pos + 1) < 0)
+ return -1;
+
+ for (i = *len; i <= pos; i++)
+ (*cpuids)[i].function = i + ext;
+ *len = pos + 1;
+ }
+
+ x86cpuidSetBits((*cpuids) + pos, cpuid);
+
+ return 0;
+}
+
+
static void
x86DataSubtract(union cpuData *data1,
const union cpuData *data2)
@@ -318,6 +368,27 @@ x86DataToCPUFeatures(virCPUDefPtr cpu,
}
+/* also removes bits corresponding to vendor string from data */
+static const struct x86_vendor *
+x86DataToVendor(union cpuData *data,
+ const struct x86_map *map)
+{
+ const struct x86_vendor *vendor = map->vendors;
+ struct cpuX86cpuid *cpuid;
+
+ while (vendor) {
+ if ((cpuid = x86DataCpuid(data, vendor->cpuid.function)) &&
+ x86cpuidMatchMasked(cpuid, &vendor->cpuid)) {
+ x86cpuidClearBits(cpuid, &vendor->cpuid);
+ return vendor;
+ }
+ vendor = vendor->next;
+ }
+
+ return NULL;
+}
+
+
static virCPUDefPtr
x86DataToCPU(const union cpuData *data,
const struct x86_model *model,
@@ -326,6 +397,7 @@ x86DataToCPU(const union cpuData *data,
virCPUDefPtr cpu;
union cpuData *copy = NULL;
union cpuData *modelData = NULL;
+ const struct x86_vendor *vendor;
if (VIR_ALLOC(cpu) < 0 ||
!(cpu->model = strdup(model->name)) ||
@@ -333,6 +405,10 @@ x86DataToCPU(const union cpuData *data,
!(modelData = x86DataFromModel(model)))
goto no_memory;
+ if ((vendor = x86DataToVendor(copy, map)) &&
+ !(cpu->vendor = strdup(vendor->name)))
+ goto no_memory;
+
x86DataSubtract(copy, modelData);
x86DataSubtract(modelData, data);
@@ -358,6 +434,106 @@ error:
static void
+x86VendorFree(struct x86_vendor *vendor)
+{
+ if (!vendor)
+ return;
+
+ VIR_FREE(vendor->name);
+ VIR_FREE(vendor);
+};
+
+
+static struct x86_vendor *
+x86VendorFind(const struct x86_map *map,
+ const char *name)
+{
+ struct x86_vendor *vendor;
+
+ vendor = map->vendors;
+ while (vendor) {
+ if (STREQ(vendor->name, name))
+ return vendor;
+
+ vendor = vendor->next;
+ }
+
+ return NULL;
+}
+
+
+static int
+x86VendorLoad(xmlXPathContextPtr ctxt,
+ struct x86_map *map)
+{
+ struct x86_vendor *vendor = NULL;
+ char *string = NULL;
+ int ret = 0;
+
+ if (VIR_ALLOC(vendor) < 0)
+ goto no_memory;
+
+ vendor->name = virXPathString("string(@name)", ctxt);
+ if (!vendor->name) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing CPU vendor name"));
+ goto ignore;
+ }
+
+ if (x86VendorFind(map, vendor->name)) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ _("CPU vendor %s already defined"), vendor->name);
+ goto ignore;
+ }
+
+ string = virXPathString("string(@string)", ctxt);
+ if (!string) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing vendor string for CPU vendor %s"), vendor->name);
+ goto ignore;
+ }
+ if (strlen(string) != VENDOR_STRING_LENGTH) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid CPU vendor string '%s'"), string);
+ goto ignore;
+ }
+
+ vendor->cpuid.function = 0;
+ vendor->cpuid.ebx = (string[0] ) |
+ (string[1] << 8) |
+ (string[2] << 16) |
+ (string[3] << 24);
+ vendor->cpuid.edx = (string[4] ) |
+ (string[5] << 8) |
+ (string[6] << 16) |
+ (string[7] << 24);
+ vendor->cpuid.ecx = (string[8] ) |
+ (string[9] << 8) |
+ (string[10] << 16) |
+ (string[11] << 24);
+
+ if (!map->vendors)
+ map->vendors = vendor;
+ else {
+ vendor->next = map->vendors;
+ map->vendors = vendor;
+ }
+
+out:
+ VIR_FREE(string);
+
+ return ret;
+
+no_memory:
+ virReportOOMError();
+ ret = -1;
+ignore:
+ x86VendorFree(vendor);
+ goto out;
+}
+
+
+static void
x86FeatureFree(struct x86_feature *feature)
{
if (feature == NULL)
@@ -389,9 +565,8 @@ x86FeatureFind(const struct x86_map *map,
static int
x86FeatureLoad(xmlXPathContextPtr ctxt,
- void *data)
+ struct x86_map *map)
{
- struct x86_map *map = data;
xmlNodePtr *nodes = NULL;
xmlNodePtr ctxt_node = ctxt->node;
struct x86_feature *feature = NULL;
@@ -500,6 +675,7 @@ x86ModelCopy(const struct x86_model *model)
return NULL;
}
+ copy->vendor = model->vendor;
copy->ncpuid = model->ncpuid;
for (i = 0; i < model->ncpuid; i++)
copy->cpuid[i] = model->cpuid[i];
@@ -788,11 +964,11 @@ x86ModelCompare(const struct x86_model *model1,
static int
x86ModelLoad(xmlXPathContextPtr ctxt,
- void *data)
+ struct x86_map *map)
{
- struct x86_map *map = data;
xmlNodePtr *nodes = NULL;
struct x86_model *model = NULL;
+ char *vendor = NULL;
int ret = 0;
int i;
int n;
@@ -832,11 +1008,22 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
if (VIR_ALLOC_N(model->cpuid, ancestor->ncpuid) < 0)
goto no_memory;
+ model->vendor = ancestor->vendor;
model->ncpuid = ancestor->ncpuid;
memcpy(model->cpuid, ancestor->cpuid,
sizeof(*model->cpuid) * model->ncpuid);
}
+ vendor = virXPathString("string(./vendor/@name)", ctxt);
+ if (vendor) {
+ if (!(model->vendor = x86VendorFind(map, vendor))) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown vendor %s referenced by CPU model %s"),
+ vendor, model->name);
+ goto ignore;
+ }
+ }
+
n = virXPathNodeSet("./feature", ctxt, &nodes);
if (n < 0)
goto ignore;
@@ -872,6 +1059,7 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
}
out:
+ VIR_FREE(vendor);
VIR_FREE(nodes);
return ret;
@@ -907,6 +1095,28 @@ x86MapFree(struct x86_map *map)
}
+static int
+x86MapLoadCallback(enum cpuMapElement element,
+ xmlXPathContextPtr ctxt,
+ void *data)
+{
+ struct x86_map *map = data;
+
+ switch (element) {
+ case CPU_MAP_ELEMENT_VENDOR:
+ return x86VendorLoad(ctxt, map);
+ case CPU_MAP_ELEMENT_FEATURE:
+ return x86FeatureLoad(ctxt, map);
+ case CPU_MAP_ELEMENT_MODEL:
+ return x86ModelLoad(ctxt, map);
+ case CPU_MAP_ELEMENT_LAST:
+ break;
+ }
+
+ return 0;
+}
+
+
static struct x86_map *
x86LoadMap(void)
{
@@ -917,9 +1127,7 @@ x86LoadMap(void)
return NULL;
}
- if (cpuMapLoad("x86",
- x86FeatureLoad, map,
- x86ModelLoad, map) < 0)
+ if (cpuMapLoad("x86", x86MapLoadCallback, map) < 0)
goto error;
return map;
@@ -965,6 +1173,13 @@ x86Compute(virCPUDefPtr host,
}
}
+ if (cpu->vendor &&
+ (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
+ VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
+ cpu->vendor);
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
+ }
+
if (!(map = x86LoadMap()) ||
!(host_model = x86ModelFromCPU(host, map, 0)) ||
!(cpu_force = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORCE)) ||
@@ -1117,6 +1332,15 @@ x86Decode(virCPUDefPtr cpu,
if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
goto out;
+ if (candidate->vendor && cpuCandidate->vendor &&
+ STRNEQ(candidate->vendor->name, cpuCandidate->vendor)) {
+ VIR_DEBUG("CPU vendor %s of model %s differs from %s; ignoring",
+ candidate->vendor->name, candidate->name,
+ cpuCandidate->vendor);
+ virCPUDefFree(cpuCandidate);
+ goto next;
+ }
+
if (cpu->type == VIR_CPU_TYPE_HOST) {
cpuCandidate->type = VIR_CPU_TYPE_HOST;
for (i = 0; i < cpuCandidate->nfeatures; i++) {
@@ -1154,6 +1378,7 @@ x86Decode(virCPUDefPtr cpu,
}
cpu->model = cpuModel->model;
+ cpu->vendor = cpuModel->vendor;
cpu->nfeatures = cpuModel->nfeatures;
cpu->features = cpuModel->features;
VIR_FREE(cpuModel);
@@ -1194,7 +1419,8 @@ x86Encode(const virCPUDefPtr cpu,
union cpuData **required,
union cpuData **optional,
union cpuData **disabled,
- union cpuData **forbidden)
+ union cpuData **forbidden,
+ union cpuData **vendor)
{
struct x86_map *map = NULL;
union cpuData *data_forced = NULL;
@@ -1202,6 +1428,7 @@ x86Encode(const virCPUDefPtr cpu,
union cpuData *data_optional = NULL;
union cpuData *data_disabled = NULL;
union cpuData *data_forbidden = NULL;
+ union cpuData *data_vendor = NULL;
int ret = -1;
if ((map = x86LoadMap()) == NULL)
@@ -1237,6 +1464,23 @@ x86Encode(const virCPUDefPtr cpu,
goto error;
}
+ if (vendor) {
+ const struct x86_vendor *v = NULL;
+
+ if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
+ virCPUReportError(VIR_ERR_OPERATION_FAILED,
+ _("CPU vendor %s not found"), cpu->vendor);
+ goto error;
+ }
+
+ if (v &&
+ (VIR_ALLOC(data_vendor) < 0 ||
+ x86DataAddCpuid(data_vendor, &v->cpuid) < 0)) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+
if (forced)
*forced = data_forced;
if (required)
@@ -1247,6 +1491,8 @@ x86Encode(const virCPUDefPtr cpu,
*disabled = data_disabled;
if (forbidden)
*forbidden = data_forbidden;
+ if (vendor)
+ *vendor = data_vendor;
ret = 0;
@@ -1261,6 +1507,7 @@ error:
x86DataFree(data_optional);
x86DataFree(data_disabled);
x86DataFree(data_forbidden);
+ x86DataFree(data_vendor);
goto cleanup;
}
@@ -1358,6 +1605,8 @@ x86Baseline(virCPUDefPtr *cpus,
union cpuData *data = NULL;
virCPUDefPtr cpu = NULL;
unsigned int i;
+ const struct x86_vendor *vendor = NULL;
+ struct x86_model *model = NULL;
if (!(map = x86LoadMap()))
goto error;
@@ -1371,13 +1620,49 @@ x86Baseline(virCPUDefPtr *cpus,
cpu->type = VIR_CPU_TYPE_GUEST;
cpu->match = VIR_CPU_MATCH_EXACT;
+ if (cpus[0]->vendor &&
+ !(vendor = x86VendorFind(map, cpus[0]->vendor))) {
+ virCPUReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unknown CPU vendor %s"), cpus[0]->vendor);
+ goto error;
+ }
+
for (i = 1; i < ncpus; i++) {
- struct x86_model *model;
+ const char *vn = NULL;
+
if (!(model = x86ModelFromCPU(cpus[i], map, 0)))
goto error;
+ if (cpus[i]->vendor && model->vendor &&
+ STRNEQ(cpus[i]->vendor, model->vendor->name)) {
+ virCPUReportError(VIR_ERR_OPERATION_FAILED,
+ _("CPU vendor %s of model %s differs from vendor %s"),
+ model->vendor->name, model->name, cpus[i]->vendor);
+ goto error;
+ }
+
+ if (cpus[i]->vendor)
+ vn = cpus[i]->vendor;
+ else if (model->vendor)
+ vn = model->vendor->name;
+
+ if (vn) {
+ if (!vendor) {
+ if (!(vendor = x86VendorFind(map, vn))) {
+ virCPUReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unknown CPU vendor %s"), vn);
+ goto error;
+ }
+ } else if (STRNEQ(vendor->name, vn)) {
+ virCPUReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("CPU vendors do not match"));
+ goto error;
+ }
+ }
+
x86ModelIntersect(base_model, model);
x86ModelFree(model);
+ model = NULL;
}
if (!(data = x86DataFromModel(base_model)))
@@ -1389,6 +1674,9 @@ x86Baseline(virCPUDefPtr *cpus,
goto error;
}
+ if (vendor && x86DataAddCpuid(data, &vendor->cpuid) < 0)
+ goto no_memory;
+
if (x86Decode(cpu, data, models, nmodels, NULL) < 0)
goto error;
@@ -1404,6 +1692,7 @@ cleanup:
no_memory:
virReportOOMError();
error:
+ x86ModelFree(model);
virCPUDefFree(cpu);
cpu = NULL;
goto cleanup;
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
index 7fee21a..99b1f4e 100644
--- a/tests/testutilsqemu.c
+++ b/tests/testutilsqemu.c
@@ -83,6 +83,7 @@ virCapsPtr testQemuCapsInit(void) {
0, /* match */
(char *) "x86_64", /* arch */
(char *) "core2duo", /* model */
+ (char *) "Intel", /* vendor */
1, /* sockets */
2, /* cores */
1, /* threads */
--
1.7.1.1
14 years, 4 months
[libvirt] A problem about live migration of kvm
by 姚远
>From qemu-kvm-0.12.1, kvm has the function about live migration with
non-shared storage. But I don't know how to use it. In the qemu monitor,
"migrate -d tcp:10.1.10.42:444" which is based on shared storage is going
well. I don't know how to use the command of "-b or -i" or maybe I don't
know the correct format of uri.
the source and destination system is Fedora-13, and the version of kvm is
qemu-kvm-0.12.3. When I use the "migrate -d -b tcp:10.1.10.42:4444", the
qemu monitor don't show nothing. When I use "info migrate",there shows
"migrate status:failed". I don't know why? I hope someone who used this
command successfully would help me, thank you.
14 years, 4 months