[libvirt] [PATCH] virsh: A bit smarter attach-disk
by Osier Yang
Detects the file type of source path if no "--sourcetype" and
"driver" is specified, instead of always set the disk type as
"block".
And previous "virCommandOptString" ensures "source" is not NULL,
remove the conditional checking.
---
tools/virsh.c | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index d45a4c9..3b845ac 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -14428,6 +14428,7 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
const char *stype = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *xml;
+ struct stat st;
if (!vshConnectionUsability(ctl, ctl->conn))
goto cleanup;
@@ -14458,8 +14459,12 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
}
if (!stype) {
- if (driver && (STREQ(driver, "file") || STREQ(driver, "tap")))
+ if (driver && (STREQ(driver, "file") || STREQ(driver, "tap"))) {
isFile = true;
+ } else {
+ if (!stat(source, &st))
+ isFile = S_ISREG(st.st_mode) ? true : false;
+ }
} else if (STREQ(stype, "file")) {
isFile = true;
} else if (STRNEQ(stype, "block")) {
@@ -14497,10 +14502,9 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
if (driver || subdriver || cache)
virBufferAddLit(&buf, "/>\n");
- if (source)
- virBufferAsprintf(&buf, " <source %s='%s'/>\n",
- (isFile) ? "file" : "dev",
- source);
+ virBufferAsprintf(&buf, " <source %s='%s'/>\n",
+ (isFile) ? "file" : "dev",
+ source);
virBufferAsprintf(&buf, " <target dev='%s'/>\n", target);
if (mode)
virBufferAsprintf(&buf, " <%s/>\n", mode);
--
1.7.1
12 years, 7 months
Re: [libvirt] [Qemu-trivial] do_spice_init error on Ubuntu11.10
by Stefan Hajnoczi
On Thu, Mar 08, 2012 at 11:29:48AM +0800, suyi wang wrote:
> Hi all:
Hi Suyi,
qemu-trivial is a mailing list for QEMU patches, questions should be
directed at the regular QEMU mailing list. I have CCed qemu-devel and
libvirt-list so your question will go to the QEMU and libvirt
communities.
Are you sure your libvirt configuration allows the QEMU process to
access /dev/shm? You may have SELinux enabled.
Stefan
> I tried kvm on my ubuntu with the libvirt.xml file as follows:
> <domain type='kvm'>
> <name>instance-00000011</
> name>
> <memory>2097152</memory>
> <os>
> <type>hvm</type>
> <boot dev="hd" />
> </os>
> <features>
> <acpi/>
> </features>
> <vcpu>1</vcpu>
> <devices>
> <sound model='ac97'/>
> <input type='tablet' bus='usb'/>
> <disk type='file'>
> <driver type='qcow2'/>
> <source
> file='/opt/stack/nova/nova/../
> /instances/instance-00000011/disk'/>
> <target dev='vda' bus='ide'/>
> </disk>
> <disk type='file'>
> <driver type='qcow2'/>
> <source
>
> - Ignored:
> file='/opt/stack/nova/nova/..//instances/instance-00000011/disk.local'/>
> <target dev='vdb' bus='ide'/>
> </disk>
>
> <interface type='bridge'>
> <source bridge='br100'/>
> <mac address='02:16:3e:44:a1:dd'/>
> <filterref
> filter="nova-instance-instance-00000011-02163e44a1dd">
> <parameter name="IP" value="10.0.0.2" />
> <parameter name="DHCPSERVER" value="10.0.0.1" />
> </filterref>
> </interface>
>
> <!-- The order is significant here. File must be defined first
> -->
> <serial type="file">
> <source
> path='/opt/stack/nova/nova/..//instances/instance-00000011/console.log'/>
> <target port='1'/>
> </serial>
>
> <console type='pty' tty='/dev/pts/2'>
> <source path='/dev/pts/2'/>
> <target port='0'/>
> </console>
>
> <serial type='pty'>
> <source path='/dev/pts/2'/>
> <target port='0'/>
> </serial>
>
>
> <graphics type='vnc' port='-1' autoport='yes' keymap='en-us'
> listen='0.0.0.0'/>
>
> </devices>
> </domain>
>
> So it works well.
>
> Howerver, I want change the remote access method by spice, I simply
> changed
> the libvirt.xml as follows:
> <domain type='kvm'>
> <name>instance-00000011</name>
> <memory>2097152</memory>
> <os>
> <type>hvm</type>
> <boot dev="hd" />
> </os>
> <features>
> <acpi/>
> </features>
> <vcpu>1</vcpu>
> <devices>
> <sound model='ac97'/>
> <input type='tablet' bus='usb'/>
> <disk type='file'>
> <driver type='qcow2'/>
> <source
> file='/opt/stack/nova/nova/..//instances/instance-00000011/disk'/>
> <target dev='vda' bus='ide'/>
> </disk>
> <disk type='file'>
> <driver type='qcow2'/>
> <source
> file='/opt/stack/nova/nova/..//instances/instance-00000011/disk.local'/>
> <target dev='vdb' bus='ide'/>
> </disk>
>
> <interface type='bridge'>
> <source bridge='br100'/>
> <mac address='02:16:3e:44:a1:dd'/>
> <filterref
> filter="nova-instance-instance-00000011-02163e44a1dd">
> <parameter name="IP" value="10.0.0.2" />
> <parameter name="DHCPSERVER" value="10.0.0.1" />
> </filterref>
> </interface>
>
> <!-- The order is significant here. File must be defined first
> -->
> <serial type="file">
> <source
> path='/opt/stack/nova/nova/..//instances/instance-00000011/console.log'/>
> <target port='1'/>
> </serial>
>
> <console type='pty' tty='/dev/pts/2'>
> <source path='/dev/pts/2'/>
> <target port='0'/>
> </console>
>
> <serial type='pty'>
> <source path='/dev/pts/2'/>
> <target port='0'/>
> </serial>
>
>
> <graphics type='spice' port='-1' autoport='yes' keymap='en-us'
> listen='0.0.0.0'/>
>
> </devices>
> </domain>
>
> As you can see, I just change <graphics type='vnc' port='-1'
> autoport='yes'
> keymap='en-us' listen='0.0.0.0'/> to <graphics type='spice' port='-1'
> autoport='yes' keymap='en-us' listen='0.0.0.0'/> , But it called the
> error as follows:
>
> libvirtError: internal error Process exited while reading console log
> output: char device redirected to /dev/pts/12
> TRACE: do_spice_init: starting 0.8.1
> TRACE: do_spice_init: statistics shm_open failed, Permission denied"
>
>
> Then I also tried "ls -ld /dev/shm" , yes, it is already 777.
> then my problem remained:
> libvirtError: internal error Process exited while reading console log
> output: char device redirected to /dev/pts/12
> TRACE: do_spice_init: starting 0.8.1
> TRACE: do_spice_init: statistics shm_open failed, Permission denied"
>
>
> I wish someone can give me some help! Thanks!
>
> --
> Yours.
> suyi
12 years, 7 months
[libvirt] [PATCH] virsh: fix invalid free
by Alex Jia
* tools/virsh.c (cmdDetachDisk): fix invalid free due to using
uninitialised value.
* How to reproduce?
# virsh detach-disk a b
error: failed to get domain 'a'
*** glibc detected *** virsh: double free or corruption (out): 0x00007fff410ed1a0 ***
======= Backtrace: =========
/lib64/libc.so.6[0x39cf0750c6]
/usr/lib/libvirt.so.0(virFree+0x39)[0x7f045938a239]
virsh[0x41c768]
virsh[0x415075]
virsh[0x425d64]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x39cf01ecdd]
virsh[0x40a419]
======= Memory map: ========
00400000-0044e000 r-xp 00000000 08:0e 760441 /usr/bin/virsh
0064e000-00650000 rw-p 0004e000 08:0e 760441 /usr/bin/virsh
......
39d7229000-39d722b000 r--p 00029000 08:0e 2183477 /lib64/libk5crypto.so.3.1
39d722b000-39d722c000 rw-p 0002b000 08:0e 2183477 /lib64/lAborted (core dumped)
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
tools/virsh.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 630b77f..d45a4c9 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -14826,7 +14826,7 @@ cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
char *disk_xml = NULL;
virDomainPtr dom = NULL;
const char *target = NULL;
- char *doc;
+ char *doc = NULL;
int ret;
bool functionReturn = false;
unsigned int flags;
--
1.7.1
12 years, 7 months
[libvirt] [PATCH 1/1] conf, util: on restart of libvirt restart vepa callbacks
by D. Herrendoerfer
From: "D. Herrendoerfer" <d.herrendoerfer(a)herrendoerfer.name>
When libvirtd is restarted, also restart the netlink event
message callbacks for existing VEPA connections and send
a message to lldpad for these existing links, so it learns
the new libvirtd pid.
Note: This Patch provides fixes to a number of scenarios where
lldpad, switch, and libvirt would loose syncronization.
1. Crash/Reboot of a switch.
2. lldpad crash.
3. Clearing of the local switch database. (cleanvms)
4. libvirtd crash or restart.
In any of the above events restarting libvirtd will restore normal
operations of the VMs on their virtual network.
Signed-off-by: D. Herrendoerfer <d.herrendoerfer(a)herrendoerfer.name>
---
src/conf/domain_conf.c | 18 ++++++
src/util/virnetdevmacvlan.c | 128 +++++++++++++++++++++++++++++++++---------
src/util/virnetdevmacvlan.h | 9 +++
3 files changed, 127 insertions(+), 28 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b994718..2ea3ea7 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -52,6 +52,7 @@
#include "secret_conf.h"
#include "netdev_vport_profile_conf.h"
#include "netdev_bandwidth_conf.h"
+#include "virnetdevmacvlan.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -4545,6 +4546,23 @@ virDomainNetDefParseXML(virCapsPtr caps,
if ((flags & VIR_DOMAIN_XML_INACTIVE))
VIR_FREE(ifname);
+ else {
+ char *tmp;
+ VIR_DEBUG("Device already active on %s in VEPA mode.",ifname);
+
+ tmp = virXPathString("string(../../uuid[1])", ctxt);
+
+ if (tmp) {
+ VIR_DEBUG("Active VM UUID: %s. Restarting association and callback handler.",tmp);
+ ignore_value(virNetDevMacVLanRestartWithVPortProfile(ifname,
+ def->mac,
+ def->data.direct.linkdev,
+ tmp,
+ def->data.direct.virtPortProfile,
+ VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
+ VIR_FREE(tmp);
+ }
+ }
break;
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index 647679f..19daf57 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -769,6 +769,49 @@ virNetDevMacVLanVPortProfileDestroyCallback(int watch ATTRIBUTE_UNUSED,
virNetlinkCallbackDataFree((virNetlinkCallbackDataPtr)opaque);
}
+static int
+virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+{
+ virNetlinkCallbackDataPtr calld = NULL;
+
+ if (virtPortProfile && virNetlinkEventServiceIsRunning()) {
+ if (VIR_ALLOC(calld) < 0)
+ goto memory_error;
+ if ((calld->cr_ifname = strdup(ifname)) == NULL)
+ goto memory_error;
+ if (VIR_ALLOC(calld->virtPortProfile) < 0)
+ goto memory_error;
+ memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
+ if (VIR_ALLOC_N(calld->macaddress, VIR_MAC_BUFLEN) < 0)
+ goto memory_error;
+ memcpy(calld->macaddress, macaddress, VIR_MAC_BUFLEN);
+ if ((calld->linkdev = strdup(linkdev)) == NULL)
+ goto memory_error;
+ if (VIR_ALLOC_N(calld->vmuuid, VIR_UUID_BUFLEN) < 0)
+ goto memory_error;
+ memcpy(calld->vmuuid, vmuuid, VIR_UUID_BUFLEN);
+
+ calld->vmOp = vmOp;
+
+ virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback,
+ virNetDevMacVLanVPortProfileDestroyCallback,
+ calld, macaddress);
+ }
+
+ return 0;
+
+ memory_error:
+ virReportOOMError();
+ virNetlinkCallbackDataFree(calld);
+
+ return -1;
+}
+
/**
* virNetDevMacVLanCreateWithVPortProfile:
@@ -810,7 +853,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
int retries, do_retry = 0;
uint32_t macvtapMode;
const char *cr_ifname;
- virNetlinkCallbackDataPtr calld = NULL;
int ret;
int vf = -1;
@@ -917,36 +959,12 @@ create_name:
goto disassociate_exit;
}
- if (virtPortProfile && virNetlinkEventServiceIsRunning()) {
- if (VIR_ALLOC(calld) < 0)
- goto memory_error;
- if ((calld->cr_ifname = strdup(cr_ifname)) == NULL)
- goto memory_error;
- if (VIR_ALLOC(calld->virtPortProfile) < 0)
- goto memory_error;
- memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
- if (VIR_ALLOC_N(calld->macaddress, VIR_MAC_BUFLEN) < 0)
- goto memory_error;
- memcpy(calld->macaddress, macaddress, VIR_MAC_BUFLEN);
- if ((calld->linkdev = strdup(linkdev)) == NULL)
- goto memory_error;
- if (VIR_ALLOC_N(calld->vmuuid, VIR_UUID_BUFLEN) < 0)
- goto memory_error;
- memcpy(calld->vmuuid, vmuuid, VIR_UUID_BUFLEN);
-
- calld->vmOp = vmOp;
-
- virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback,
- virNetDevMacVLanVPortProfileDestroyCallback,
- calld, macaddress);
- }
+ if (virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
+ linkdev, vmuuid, virtPortProfile, vmOp) < 0 )
+ goto disassociate_exit;
return rc;
- memory_error:
- virReportOOMError();
- virNetlinkCallbackDataFree(calld);
-
disassociate_exit:
ignore_value(virNetDevVPortProfileDisassociate(cr_ifname,
virtPortProfile,
@@ -1003,6 +1021,48 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
return ret;
}
+/**
+ * virNetDevMacVLanRestartWithVPortProfile:
+ * Register a port profile callback handler for a VM that
+ * is already running
+ * .
+ * @cr_ifname: Interface name that the macvtap has.
+ * @macaddress: The MAC address for the macvtap device
+ * @linkdev: The interface name of the NIC to connect to the external bridge
+ * @vmuuid: The UUID of the VM the macvtap belongs to
+ * @virtPortProfile: pointer to object holding the virtual port profile data
+ * @vmOp: Operation to use during setup of the association
+ *
+ * Returns 0; returns -1 on error.
+ */
+int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+{
+ int rc = 0;
+
+ rc = virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
+ linkdev, vmuuid,
+ virtPortProfile, vmOp);
+ if (rc < 0)
+ goto error;
+
+ ignore_value(virNetDevVPortProfileAssociate(cr_ifname,
+ virtPortProfile,
+ macaddress,
+ linkdev,
+ -1,
+ vmuuid,
+ vmOp, true));
+
+error:
+ return rc;
+
+}
+
#else /* ! WITH_MACVTAP */
int virNetDevMacVLanCreate(const char *ifname ATTRIBUTE_UNUSED,
const char *type ATTRIBUTE_UNUSED,
@@ -1052,4 +1112,16 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname ATTRIBUTE_UNUSED,
_("Cannot create macvlan devices on this platform"));
return -1;
}
+
+int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Cannot create macvlan devices on this platform"));
+ return -1;
+}
#endif /* ! WITH_MACVTAP */
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
index 130ecea..14640cf 100644
--- a/src/util/virnetdevmacvlan.h
+++ b/src/util/virnetdevmacvlan.h
@@ -75,4 +75,13 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_NONNULL(6) ATTRIBUTE_RETURN_CHECK;
+int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+ ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK;
+
#endif /* __UTIL_MACVTAP_H__ */
--
1.7.7.6
12 years, 7 months
[libvirt] [PATCH] Split contents of <cmdline>...</cmdline> and set LXC init argv
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Currently for LXC we set LIBVIRT_LXC_CMDLINE to contain the
contents of <cmdline>...</cmdline>. It is more convenient
if we just set the argv[] of the init binary directly though.
* lxc/lxc_container.c: Set init argv from cmdline
---
src/lxc/lxc_container.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index d827b35..93dfb86 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -117,11 +117,19 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
virCommandPtr cmd;
+ char **args = NULL;
+ size_t i;
+
+ if (vmDef->os.cmdline &&
+ !(args = virStrSplitQuoted(vmDef->os.cmdline, " \t")))
+ return NULL;
virUUIDFormat(vmDef->uuid, uuidstr);
cmd = virCommandNew(vmDef->os.init);
+ virCommandAddArgSet(cmd, (const char **)args);
+
virCommandAddEnvString(cmd, "PATH=/bin:/sbin");
virCommandAddEnvString(cmd, "TERM=linux");
virCommandAddEnvString(cmd, "container=lxc-libvirt");
@@ -131,6 +139,10 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef)
if (vmDef->os.cmdline)
virCommandAddEnvPair(cmd, "LIBVIRT_LXC_CMDLINE", vmDef->os.cmdline);
+ for (i = 0 ; args[i] ; i++)
+ VIR_FREE(args[i]);
+ VIR_FREE(args);
+
return cmd;
}
--
1.7.7.6
12 years, 7 months
[libvirt] [PATCH] Add a virStrSplitQuoted for splitting quoted strings
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
To facilitate parsing of argv[] style strings, provide a
virStrSplitQuoted API which will split a string on the listed
separators, but also allow for quoting with ' or ".
* src/libvirt_private.syms, src/util/util.c,
src/util/util.h: Implement virStrSplitQuoted
* tests/utiltest.c: Some tests for virStrSplitQuoted
---
src/libvirt_private.syms | 1 +
src/util/util.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/util.h | 2 +
tests/utiltest.c | 89 ++++++++++++++++++++++++++++++++--
4 files changed, 203 insertions(+), 6 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1f55f5d..b6fbafc 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1148,6 +1148,7 @@ virSetUIDGID;
virSkipSpaces;
virSkipSpacesAndBackslash;
virSkipSpacesBackwards;
+virStrSplitQuoted;
virStrToDouble;
virStrToLong_i;
virStrToLong_l;
diff --git a/src/util/util.c b/src/util/util.c
index 15e6cfa..acfb033 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1951,6 +1951,123 @@ virStrcpy(char *dest, const char *src, size_t destbytes)
return virStrncpy(dest, src, strlen(src), destbytes);
}
+
+static char *
+virStrDupUnescape(const char *src, size_t len)
+{
+ char *ret;
+ size_t i, j;
+ bool escape = false;
+
+ if (VIR_ALLOC_N(ret, len + 1) < 0)
+ return NULL;
+
+ for (i = 0, j = 0 ; i < len ; i++) {
+ if (escape) {
+ escape = false;
+ ret[j++] = src[i];
+ } else if (src[i] == '\\') {
+ escape = true;
+ } else {
+ ret[j++] = src[i];
+ }
+ }
+ ret[j++] = '\0';
+
+ return ret;
+}
+
+/**
+ * virStrSplitQuoted:
+ * @src: string to split
+ * @sep: list of separator characters
+ *
+ * Split the string 'src' into chunks, separated by one or more of
+ * the characters in 'sep'. Allow ' or " to quote strings even if
+ * they contain 'sep'
+ *
+ * Returns NULL terminated array of strings
+ */
+char **
+virStrSplitQuoted(const char *src, const char *sep)
+{
+ size_t alloc = 0;
+ size_t count = 0;
+ char **ret = NULL;
+ const char *start = src;
+ const char *end;
+ bool escape;
+ char match;
+ char *value = NULL;
+ size_t i;
+
+ while (start && *start) {
+ start += strspn(start, sep);
+
+ if (!*start)
+ break;
+
+ if (*start == '\'' || *start == '\"') {
+ match = *start;
+ start++;
+
+ for (end = start, escape = false ; *end ; end++) {
+ if (escape)
+ escape = false;
+ else if (*end == '\\')
+ escape = true;
+ else if (*end == match)
+ break;
+ }
+
+ if (VIR_RESIZE_N(ret, alloc, count, 1) < 0)
+ goto no_memory;
+
+ if (!(ret[count] = virStrDupUnescape(start, end-start)))
+ goto no_memory;
+ count++;
+
+ start = end;
+ if (*start)
+ start++;
+ } else {
+ for (end = start, escape = false ; *end ; end++) {
+ if (escape)
+ escape = false;
+ else if (*end == '\\')
+ escape = true;
+ else if (strspn(end, sep))
+ break;
+ }
+
+ if (VIR_RESIZE_N(ret, alloc, count, 1) < 0)
+ goto no_memory;
+
+ if (!(ret[count] = virStrDupUnescape(start, end-start)))
+ goto no_memory;
+ count++;
+
+ start = end;
+ if (*start)
+ start++;
+ }
+ }
+
+ if (VIR_RESIZE_N(ret, alloc, count, 1) < 0)
+ goto no_memory;
+ ret[count] = NULL;
+
+ return ret;
+
+no_memory:
+ VIR_FREE(value);
+ for (i = 0 ; i < count ; i++)
+ VIR_FREE(ret[i]);
+ VIR_FREE(ret);
+ return NULL;
+}
+
+
int virEnumFromString(const char *const*types,
unsigned int ntypes,
const char *type)
diff --git a/src/util/util.h b/src/util/util.h
index 85e8bd6..404003d 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -182,6 +182,8 @@ char *virStrcpy(char *dest, const char *src, size_t destbytes)
ATTRIBUTE_RETURN_CHECK;
# define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest))
+char **virStrSplitQuoted(const char *src, const char *sep);
+
int virDiskNameToIndex(const char* str);
char *virIndexToDiskName(int idx, const char *prefix);
diff --git a/tests/utiltest.c b/tests/utiltest.c
index 774a2f7..b8c6a8e 100644
--- a/tests/utiltest.c
+++ b/tests/utiltest.c
@@ -151,6 +151,55 @@ testParseVersionString(const void *data ATTRIBUTE_UNUSED)
}
+struct StringSplitData {
+ const char *src;
+ const char *sep;
+ const char **bits;
+};
+
+static int
+testStringSplit(const void *opaque)
+{
+ int ret = -1;
+ const struct StringSplitData *data = opaque;
+ char **actual;
+ char **tmp1;
+ const char **tmp2 = data->bits;
+ size_t i;
+
+ tmp1 = actual = virStrSplitQuoted(data->src, data->sep);
+
+ if (!tmp1)
+ return -1;
+
+ while (*tmp1 && *tmp2) {
+ if (STRNEQ(*tmp1, *tmp2)) {
+ fprintf(stderr, "Expected '%s' got '%s'\n", *tmp2, *tmp1);
+ goto cleanup;
+ }
+
+ tmp1++;
+ tmp2++;
+ }
+
+ if (*tmp1) {
+ fprintf(stderr, "Unexpected extra value '%s'\n", *tmp1);
+ goto cleanup;
+ }
+
+ if (*tmp2) {
+ fprintf(stderr, "Unexpected missing value '%s'\n", *tmp2);
+ goto cleanup;
+ }
+
+
+ ret = 0;
+cleanup:
+ for (i = 0 ; actual[i] ; i++)
+ VIR_FREE(actual[i]);
+ VIR_FREE(actual);
+ return ret;
+}
static int
@@ -161,17 +210,45 @@ mymain(void)
virSetErrorFunc(NULL, testQuietError);
#define DO_TEST(_name) \
- do { \
- if (virtTestRun("Util "#_name, 1, test##_name, \
- NULL) < 0) { \
- result = -1; \
- } \
- } while (0)
+ do { \
+ if (virtTestRun("Util "#_name, 1, test##_name, \
+ NULL) < 0) { \
+ result = -1; \
+ } \
+ } while (0)
+
+#define DO_TEST_STRING(str, sep, bits) \
+ do { \
+ struct StringSplitData data = { \
+ str, sep, bits \
+ }; \
+ if (virtTestRun("Util split " str, 1, testStringSplit, \
+ &data) < 0) { \
+ result = -1; \
+ } \
+ } while (0)
DO_TEST(IndexToDiskName);
DO_TEST(DiskNameToIndex);
DO_TEST(ParseVersionString);
+ const char *bits1[] = { "foo", "bar", NULL };
+ DO_TEST_STRING("foo bar", " ", bits1);
+ DO_TEST_STRING("foo 'bar'", " ", bits1);
+ DO_TEST_STRING("foo \"bar\"", " ", bits1);
+ DO_TEST_STRING(" foo \"bar\"", " ", bits1);
+ DO_TEST_STRING(" foo \"bar\"", " ", bits1);
+ DO_TEST_STRING(" foo \"bar\"\n ", " \t\n\r", bits1);
+
+ const char *bits2[] = { "foo", "bar wizz", "eek", NULL };
+ DO_TEST_STRING("foo 'bar wizz' eek", " ", bits2);
+ DO_TEST_STRING("foo \"bar wizz\" eek", " ", bits2);
+
+ const char *bits3[] = { "foo", "'bar' \"wizz\"", "eek", NULL };
+ DO_TEST_STRING("foo '\\'bar\\' \\\"wizz\\\"' eek", " ", bits3);
+ DO_TEST_STRING("foo \"\\'bar\\' \\\"wizz\\\"\" eek", " ", bits3);
+ DO_TEST_STRING("foo \"\\'bar\\' \\\"wizz\\\"\"\r\n eek", " \r\n", bits3);
+
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.7.7.6
12 years, 7 months
[libvirt] QEmu: support disk filenames with comma
by Crístian Viana
Hi!
This patch fixes RHBZ #801036 adding support to filenames with comma using QEmu. As this is my first patch to libvirt, I'm not completely sure if I should have also changed other parts of the code, or if I have used the wrong memory allocation functions/macros, or if I shouldn't have created a separate commit to add my name to the AUTHORS file... :-)
I also need to make it clear that this patch only fixes the problem in the "libvirt data -> QEmu args" way (e.g., when QEmu reads an XML file to start QEmu, or when using virsh domxml-to-native). The other way, "QEmu args -> libvirt data" is *not* implemented (e.g., virsh domxml-from-native). I would like to know if I'm going in the right way so I can continue working on this patch, and if that half of the feature is also needed.
Any feedback is welcome, thanks!
Best regards,
Crístian.
12 years, 7 months
[libvirt] [PATCH] qemu: Use scsi-block for lun passthrough instead of scsi-disk
by Osier Yang
And don't allow to hotplug a usb disk with "device == lun". This
is the missed pieces in previous virtio-scsi patchset:
http://www.redhat.com/archives/libvir-list/2012-February/msg01052.html
---
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 46 +++++++++++++------
src/qemu/qemu_driver.c | 14 ++++--
tests/qemuhelptest.c | 3 +-
.../qemuxml2argv-disk-scsi-lun-passthrough.args | 10 ++++
.../qemuxml2argv-disk-scsi-lun-passthrough.xml | 32 ++++++++++++++
tests/qemuxml2argvtest.c | 4 ++
8 files changed, 93 insertions(+), 20 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.xml
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 64a4546..ace5011 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -154,6 +154,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"drive-iotune", /* 85 */
"system_wakeup",
"scsi-disk.channel",
+ "scsi-block",
);
struct qemu_feature_flags {
@@ -1444,6 +1445,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags)
qemuCapsSet(flags, QEMU_CAPS_VIRTIO_BLK_SCSI);
if (strstr(str, "scsi-disk.channel"))
qemuCapsSet(flags, QEMU_CAPS_SCSI_DISK_CHANNEL);
+ if (strstr(str, "scsi-block"))
+ qemuCapsSet(flags, QEMU_CAPS_SCSI_BLOCK);
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index db584ce..62b4270 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -122,6 +122,7 @@ enum qemuCapsFlags {
QEMU_CAPS_DRIVE_IOTUNE = 85, /* -drive bps= and friends */
QEMU_CAPS_WAKEUP = 86, /* system_wakeup monitor command */
QEMU_CAPS_SCSI_DISK_CHANNEL = 87, /* Is scsi-disk.channel available? */
+ QEMU_CAPS_SCSI_BLOCK = 88, /* -device scsi-block */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 6ec1eb9..048bad8 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2190,6 +2190,15 @@ qemuBuildDriveDevStr(virDomainDefPtr def,
disk->info.addr.drive.unit);
break;
case VIR_DOMAIN_DISK_BUS_SCSI:
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SCSI_BLOCK)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support scsi-block for "
+ "lun passthrough"));
+ goto error;
+ }
+ }
+
controllerModel =
virDomainDiskFindControllerModel(def, disk,
VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
@@ -2205,30 +2214,37 @@ qemuBuildDriveDevStr(virDomainDefPtr def,
goto error;
}
- virBufferAddLit(&opt, "scsi-disk");
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN)
+ virBufferAddLit(&opt, "scsi-block");
+ else
+ virBufferAddLit(&opt, "scsi-disk");
virBufferAsprintf(&opt, ",bus=scsi%d.%d,scsi-id=%d",
disk->info.addr.drive.controller,
disk->info.addr.drive.bus,
disk->info.addr.drive.unit);
} else {
- if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_CHANNEL)) {
- if (disk->info.addr.drive.target > 7) {
- qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support target "
- "greater than 7"));
- goto error;
- }
+ if ((disk->device != VIR_DOMAIN_DISK_DEVICE_LUN)) {
+ if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_CHANNEL)) {
+ if (disk->info.addr.drive.target > 7) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support target "
+ "greater than 7"));
+ goto error;
+ }
- if ((disk->info.addr.drive.bus != disk->info.addr.drive.unit) &&
- (disk->info.addr.drive.bus != 0)) {
- qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU only supports both bus and "
- "unit equal to 0"));
- goto error;
+ if ((disk->info.addr.drive.bus != disk->info.addr.drive.unit) &&
+ (disk->info.addr.drive.bus != 0)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU only supports both bus and "
+ "unit equal to 0"));
+ goto error;
+ }
}
+ virBufferAddLit(&opt, "scsi-disk");
+ } else {
+ virBufferAddLit(&opt, "scsi-block");
}
- virBufferAddLit(&opt, "scsi-disk");
virBufferAsprintf(&opt, ",bus=scsi%d.0,channel=%d,scsi-id=%d,lun=%d",
disk->info.addr.drive.controller,
disk->info.addr.drive.bus,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index be678f3..b4878c3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5090,17 +5090,23 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
break;
case VIR_DOMAIN_DISK_DEVICE_DISK:
case VIR_DOMAIN_DISK_DEVICE_LUN:
- if (disk->bus == VIR_DOMAIN_DISK_BUS_USB)
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("disk device='lun' is not supported for usb bus"));
+ break;
+ }
ret = qemuDomainAttachUsbMassstorageDevice(conn, driver, vm,
disk);
- else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
+ } else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
ret = qemuDomainAttachPciDiskDevice(conn, driver, vm, disk);
- else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI)
+ } else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
- else
+ } else {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk bus '%s' cannot be hotplugged."),
virDomainDiskBusTypeToString(disk->bus));
+ }
break;
default:
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 370cd0d..05fdc4d 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -673,7 +673,8 @@ mymain(void)
QEMU_CAPS_VIRTIO_BLK_SCSI,
QEMU_CAPS_VIRTIO_BLK_SG_IO,
QEMU_CAPS_CPU_HOST,
- QEMU_CAPS_FSDEV_WRITEOUT);
+ QEMU_CAPS_FSDEV_WRITEOUT,
+ QEMU_CAPS_SCSI_BLOCK);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.args
new file mode 100644
index 0000000..1d2b476
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.args
@@ -0,0 +1,10 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
+pc -m 214 -smp 1 -nographic -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \
+-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 \
+-device lsi,id=scsi1,bus=pci.0,addr=0x4 \
+-drive file=/dev/HostVG/QEMUGuest1,if=none,id=drive-scsi0-0-0-0 \
+-device scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \
+-drive file=/dev/HostVG/QEMUGuest2,if=none,id=drive-scsi0-0-1-1 \
+-device scsi-block,bus=scsi0.0,channel=0,scsi-id=1,lun=1,drive=drive-scsi0-0-1-1,id=scsi0-0-1-1 \
+-usb -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.xml
new file mode 100644
index 0000000..7f0cc81
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-scsi-lun-passthrough.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='lun'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='scsi'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <disk type='block' device='lun'>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hda' bus='scsi'/>
+ <address type='drive' controller='0' bus='0' target='1' unit='1'/>
+ </disk>
+ <controller type='scsi' index='0' model='virtio-scsi'/>
+ <controller type='scsi' index='1' model='lsilogic'/>
+ <controller type='usb' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 9001834..d0affc7 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -487,6 +487,10 @@ mymain(void)
QEMU_CAPS_DRIVE,
QEMU_CAPS_DEVICE,
QEMU_CAPS_VIRTIO_BLK_SCSI, QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ DO_TEST("disk-scsi-lun-passthrough", false,
+ QEMU_CAPS_DRIVE,
+ QEMU_CAPS_DEVICE,
+ QEMU_CAPS_SCSI_BLOCK, QEMU_CAPS_VIRTIO_BLK_SG_IO);
DO_TEST("graphics-vnc", false, NONE);
DO_TEST("graphics-vnc-socket", false, NONE);
--
1.7.1
12 years, 7 months