[libvirt] [libvirt-glib 1/3] Add gvir_config_object_new{_from_xml} helpers
by Christophe Fergeau
This factors the code that is repeated in the _new methods of
all classes deriving from GVirObject
---
libvirt-gconfig/libvirt-gconfig-domain.c | 26 ++++++++++--------------
libvirt-gconfig/libvirt-gconfig-object.c | 31 ++++++++++++++++++++++++++++++
libvirt-gconfig/libvirt-gconfig-object.h | 8 +++++++
libvirt-gconfig/libvirt-gconfig.sym | 1 +
4 files changed, 51 insertions(+), 15 deletions(-)
diff --git a/libvirt-gconfig/libvirt-gconfig-domain.c b/libvirt-gconfig/libvirt-gconfig-domain.c
index 837287c..3290389 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain.c
@@ -147,27 +147,23 @@ static void gvir_config_domain_init(GVirConfigDomain *conn)
GVirConfigDomain *gvir_config_domain_new_from_xml(const gchar *xml,
GError **error)
{
- xmlNodePtr node;
+ GVirConfigObject *object;
- node = gvir_config_xml_parse(xml, "domain", error);
- if ((error != NULL) && (*error != NULL))
- return NULL;
- return GVIR_CONFIG_DOMAIN(g_object_new(GVIR_TYPE_CONFIG_DOMAIN,
- "node", node,
- "schema", DATADIR "/libvirt/schemas/domain.rng",
- NULL));
+ object = gvir_config_object_new_from_xml(GVIR_TYPE_CONFIG_DOMAIN,
+ "domain",
+ DATADIR "/libvirt/schemas/domain.rng",
+ xml, error);
+ return GVIR_CONFIG_DOMAIN(object);
}
GVirConfigDomain *gvir_config_domain_new(void)
{
- xmlDocPtr doc;
+ GVirConfigObject *object;
- doc = xmlNewDoc((xmlChar *)"1.0");
- doc->children = xmlNewDocNode(doc, NULL, (xmlChar *)"domain", NULL);
- return GVIR_CONFIG_DOMAIN(g_object_new(GVIR_TYPE_CONFIG_DOMAIN,
- "node", doc->children,
- "schema", DATADIR "/libvirt/schemas/domain.rng",
- NULL));
+ object = gvir_config_object_new(GVIR_TYPE_CONFIG_DOMAIN,
+ "domain",
+ DATADIR "/libvirt/schemas/domain.rng");
+ return GVIR_CONFIG_DOMAIN(object);
}
char *gvir_config_domain_get_name(GVirConfigDomain *domain)
diff --git a/libvirt-gconfig/libvirt-gconfig-object.c b/libvirt-gconfig/libvirt-gconfig-object.c
index e59cbcd..adbd955 100644
--- a/libvirt-gconfig/libvirt-gconfig-object.c
+++ b/libvirt-gconfig/libvirt-gconfig-object.c
@@ -355,3 +355,34 @@ void gvir_config_object_set_node_content_uint64(GVirConfigObject *object,
gvir_config_object_set_node_content(object, node_name, str);
g_free(str);
}
+
+GVirConfigObject *gvir_config_object_new_from_xml(GType type,
+ const char *root_name,
+ const char *schema,
+ const gchar *xml,
+ GError **error)
+{
+ xmlNodePtr node;
+
+ node = gvir_config_xml_parse(xml, root_name, error);
+ if ((error != NULL) && (*error != NULL))
+ return NULL;
+ return GVIR_CONFIG_OBJECT(g_object_new(type,
+ "node", node,
+ "schema", schema,
+ NULL));
+}
+
+GVirConfigObject *gvir_config_object_new(GType type,
+ const char *root_name,
+ const char *schema)
+{
+ xmlDocPtr doc;
+
+ doc = xmlNewDoc((xmlChar *)"1.0");
+ doc->children = xmlNewDocNode(doc, NULL, (xmlChar *)root_name, NULL);
+ return GVIR_CONFIG_OBJECT(g_object_new(type,
+ "node", doc->children,
+ "schema", schema,
+ NULL));
+}
diff --git a/libvirt-gconfig/libvirt-gconfig-object.h b/libvirt-gconfig/libvirt-gconfig-object.h
index c203798..52e4525 100644
--- a/libvirt-gconfig/libvirt-gconfig-object.h
+++ b/libvirt-gconfig/libvirt-gconfig-object.h
@@ -59,6 +59,14 @@ struct _GVirConfigObjectClass
GType gvir_config_object_get_type(void);
+GVirConfigObject *gvir_config_object_new(GType type,
+ const char *root_name,
+ const char *schema);
+GVirConfigObject *gvir_config_object_new_from_xml(GType type,
+ const char *root_name,
+ const char *schema,
+ const gchar *xml,
+ GError **error);
void gvir_config_object_validate(GVirConfigObject *config,
GError **err);
diff --git a/libvirt-gconfig/libvirt-gconfig.sym b/libvirt-gconfig/libvirt-gconfig.sym
index 951aac6..31a89d2 100644
--- a/libvirt-gconfig/libvirt-gconfig.sym
+++ b/libvirt-gconfig/libvirt-gconfig.sym
@@ -31,6 +31,7 @@ LIBVIRT_GOBJECT_0.0.1 {
gvir_config_object_get_type;
gvir_config_object_error_quark;
gvir_config_object_new;
+ gvir_config_object_new_from_xml;
gvir_config_object_get_schema;
gvir_config_object_get_xml_node;
gvir_config_object_to_xml;
--
1.7.7
13 years
[libvirt] [PATCH 8/8] Add tests for blkdeviotune
by Lei Li
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
.../qemuxml2argv-blkdeviotune.args | 4 ++
.../qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml | 37 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 1 +
tests/qemuxml2xmltest.c | 1 +
4 files changed, 43 insertions(+), 0 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args
new file mode 100644
index 0000000..6f34698
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args
@@ -0,0 +1,4 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
+pc -m 214 -smp 1 -name QEMUGuest1 -nographic -monitor unix:/tmp/test-monitor, \
+server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial \
+none -parallel none -usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml
new file mode 100644
index 0000000..0cabb90
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml
@@ -0,0 +1,37 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</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='disk' snapshot='internal'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <iotune>
+ <total_bytes_sec>5000</total_bytes_sec>
+ <total_iops_sec>6000</total_iops_sec>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <disk type='block' device='cdrom' snapshot='no'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index d9a6e8d..1ebb950 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -585,6 +585,7 @@ mymain(void)
DO_TEST("blkiotune", false, QEMU_CAPS_NAME);
DO_TEST("cputune", false, QEMU_CAPS_NAME);
DO_TEST("numatune-memory", false, NONE);
+ DO_TEST("blkdeviotune", false, QEMU_CAPS_NAME);
DO_TEST("multifunction-pci-device", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 3f37520..2e6b5c7 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -191,6 +191,7 @@ mymain(void)
DO_TEST("event_idx");
DO_TEST("usb-redir");
+ DO_TEST("blkdeviotune");
/* These tests generate different XML */
DO_TEST_DIFFERENT("balloon-device-auto");
--
1.7.1
13 years
[libvirt] [PATCH 6/8] Doc: Add description and validate the new XML
by Lei Li
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
docs/formatdomain.html.in | 31 +++++++++++++++++++++++++++++++
docs/schemas/domaincommon.rng | 24 ++++++++++++++++++++++++
2 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index cbad196..733062d 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -893,6 +893,14 @@
<driver name="tap" type="aio" cache="default"/>
<source file='/var/lib/xen/images/fv0'/ startupPolicy='optional'>
<target dev='hda' bus='ide'/>
+ <iotune>
+ <total_bytes_sec>n</total_bytes_sec>
+ <read_bytes_sec>n</read_bytes_sec>
+ <write_bytes_sec>n</write_bytes_sec>
+ <total_iops_sec>n</total_iops_sec>
+ <read_bytes_sec>n</read_bytes_sec>
+ <write_bytes_sec>n</write_bytes_sec>
+ </iotune>
<boot order='2'/>
<encryption type='...'>
...
@@ -1010,6 +1018,29 @@
<span class="since">Since 0.0.3; <code>bus</code> attribute since 0.4.3;
"usb" attribute value since after 0.4.4; "sata" attribute value since
0.9.7</span></dd>
+ <dt><code>iotune</code></dt>
+ <dd>The optional <code>iotune</code> element provides the ability
+ to set or get block I/O throttling for the device. Block I/O
+ throtting be implemented by qemu, is specified per-disk and can
+ vary across multiple disks.</dd>
+ <dt><code>total_bytes_sec</code></dt>
+ <dd>The optinal <code>total_bytes_sec</code> element is the total throughput
+ limit in bytes per second.</dd>
+ <dt><code>read_bytes_sec</code></dt>
+ <dd>The optinal <code>read_bytes_sec</code> element is the read throughput
+ limit in bytes per second.</dd>
+ <dt><code>write_bytes_sec</code</dt>
+ <dd>The optinal <code>write_bytes_sec</code> element is the write throughput
+ limit in bytes per second.</dd>
+ <dt><code>total_iops_sec</code></dt>
+ <dd>The optional <code>total_iops_sec</code> element is the total I/O operations
+ per second.</dd>
+ <dt><code>read_iops_sec</code></dt>
+ <dd>The optional <code>read_iops_sec</code> element is the read I/O operations
+ per second.</dd>
+ <dt><code>write_iops_sec</code></dt>
+ <dd>The optional <code>write_iops_sec</code> element is the write I/O operations
+ per second.</dd>
<dt><code>driver</code></dt>
<dd>
The optional driver element allows specifying further details
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b6f858e..c6873a0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -698,6 +698,30 @@
<optional>
<ref name="snapshot"/>
</optional>
+ <optional>
+ <element name="iotune">
+ <choice>
+ <element name="total_bytes_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="read_bytes_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="write_bytes_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="total_iops_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="read_iops_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="write_iopw_sec">
+ <ref name="unsignedLongLong">
+ </emement>
+ </choice>
+ </element>
+ </optional>
<choice>
<group>
<attribute name="type">
--
1.7.1
13 years
[libvirt] Virtual serial logging server?
by Reeted
Dear all,
please excuse the almost-OT question,
I see various possibilities in quemu-kvm and libvirt for sending virtual
serial port data to files, sockets, pipes, etc on the host.
In particular, the TCP socket seems interesting.
Can you suggest a server application to receive all such TCP connections
and log serial data for many virtual machines at once?
In particular I would be interested in something with quotas, i.e.
something that deletes old lines from the logs of a certain VM when the
filesystem space occupied by the serial logs of such VM gets over a
certain amount of space. So that the log space for other VMs is not
starved in case one of them loops.
Thank you
R.
13 years
[libvirt] [PATCH 0/2] Fix 0.9.7 for mingw
by Eric Blake
I'm proposing two options to fix the build failure mentioned here:
https://www.redhat.com/archives/libvir-list/2011-November/msg00309.html
without having to cut a release of 0.9.8.
Note that this email is presenting a diff of a diff - that is,
patch 2/2 is a diff that creates two new files, whose contents are
then diffs themselves; it is those resulting diffs that get used in
two contexts - the gnulib local diffs when building libvirt.git, and
the application of those diffs to the non-version-controlled
libvirt-0.9.7/gnulib/lib files when backporting the changes for
building a mingw rpm. Hopefully that doesn't confuse you too much.
Option 1: Upstream applies both of these patches, then the fix for
building the mingw32-libvirt RPM would be to take the resulting diff
files in patch 2/2 and apply those directly to the gnulib/lib files
present in the 0.9.7 tarball expansion (no .gnulib submodule updated,
and no gnulib-tool run introduced into the spec file). Later, when
upstream gnulib is fixed, we revert patch 2/2 at the same time we
update our .gnulib submodule.
Option 2 would be to apply patch 1/2, but then wait until the fixes
in patch 2/2 are present in upstream gnulib, and just update
.gnulib directly instead of bothering with local diffs.
Personally, I prefer option 1. I've tested this by running
./autobuild.sh, which builds both Linux and cross-builds to mingw,
validating that the diffs apply correctly so that mingw builds.
Eric Blake (2):
build: allow for local gnulib diffs
build: fix mingw build of gnulib openpty
autogen.sh | 3 +++
bootstrap.conf | 6 ++++--
cfg.mk | 1 +
gnulib/local/lib/openpty.c.diff | 26 ++++++++++++++++++++++++++
gnulib/local/lib/pty.in.h.diff | 13 +++++++++++++
5 files changed, 47 insertions(+), 2 deletions(-)
create mode 100644 gnulib/local/lib/openpty.c.diff
create mode 100644 gnulib/local/lib/pty.in.h.diff
--
1.7.4.4
13 years
[libvirt] [PATCH] Allow non-blocking message sending on virNetClient
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Split the existing virNetClientSend into two parts
virNetClientSend and virNetClientSendNoReply, instead
of having a 'bool expectReply' parameter.
Add a new virNetClientSendNonBlock which returns 2 on
full send, 1 on partial send, 0 on no send, -1 on error
If a partial send occurs, then a subsequent call to any
of the virNetClientSend* APIs will finish any outstanding
I/O.
TODO: the virNetClientEvent event handler could be used
to speed up completion of partial sends if an event loop
is present.
* src/rpc/virnetclientprogram.c, src/rpc/virnetclientstream.c:
Update for changed API
---
src/rpc/virnetclient.c | 249 +++++++++++++++++++++++++++++++++-------
src/rpc/virnetclient.h | 12 ++-
src/rpc/virnetclientprogram.c | 2 +-
src/rpc/virnetclientstream.c | 11 ++-
4 files changed, 224 insertions(+), 50 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 4b7d4a9..b0ed507 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -55,6 +55,8 @@ struct _virNetClientCall {
virNetMessagePtr msg;
bool expectReply;
+ bool nonBlock;
+ bool haveThread;
virCond cond;
@@ -86,8 +88,15 @@ struct _virNetClient {
int wakeupSendFD;
int wakeupReadFD;
- /* List of threads currently waiting for dispatch */
+ /*
+ * List of calls currently waiting for dispatch
+ * The calls should all have threads waiting for
+ * them, except possibly the first call in the list
+ * which might be a partially sent non-blocking call.
+ */
virNetClientCallPtr waitDispatch;
+ /* Whether a thread is dispatching */
+ bool haveTheBuck;
size_t nstreams;
virNetClientStreamPtr *streams;
@@ -555,7 +564,7 @@ virNetClientCallDispatchReply(virNetClientPtr client)
virNetClientCallPtr thecall;
/* Ok, definitely got an RPC reply now find
- out who's been waiting for it */
+ out which waiting call is associated with it */
thecall = client->waitDispatch;
while (thecall &&
!(thecall->msg->header.prog == client->msg.header.prog &&
@@ -896,10 +905,31 @@ virNetClientIOHandleInput(virNetClientPtr client)
}
+static void virNetClientPassTheBuck(virNetClientPtr client)
+{
+ virNetClientCallPtr tmp = client->waitDispatch;
+
+ /* See if someone else is still waiting
+ * and if so, then pass the buck ! */
+ while (tmp) {
+ if (tmp->haveThread) {
+ VIR_DEBUG("Passing the buck to %p", tmp);
+ virCondSignal(&tmp->cond);
+ return;
+ }
+ tmp = tmp->next;
+ }
+ VIR_DEBUG("No thread to pass the buck to");
+}
+
+
/*
* Process all calls pending dispatch/receive until we
* get a reply to our own call. Then quit and pass the buck
* to someone else.
+ *
+ * Returns 2 if fully sent, 1 if partially sent (only for nonBlock==true),
+ * 0 if nothing sent (only for nonBlock==true) and -1 on error
*/
static int virNetClientIOEventLoop(virNetClientPtr client,
virNetClientCallPtr thiscall)
@@ -924,6 +954,12 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
if (virNetSocketHasCachedData(client->sock))
timeout = 0;
+ /* If we're a non-blocking call, then we don't
+ * want to wait for I/O readyness
+ */
+ if (thiscall->nonBlock)
+ timeout = 0;
+
fds[0].events = fds[0].revents = 0;
fds[1].events = fds[1].revents = 0;
@@ -975,8 +1011,34 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
/* If we have existing SASL decoded data, pretend
* the socket became readable so we consume it
*/
- if (virNetSocketHasCachedData(client->sock))
+ if (virNetSocketHasCachedData(client->sock)) {
fds[0].revents |= POLLIN;
+ } else if (ret == 0 && thiscall->nonBlock) {
+ if (thiscall->msg->bufferOffset == 0) {
+ /* No data sent at all, remove ourselves from the list */
+ tmp = client->waitDispatch;
+ prev = NULL;
+ while (tmp) {
+ if (tmp == thiscall) {
+ if (prev) {
+ prev->next = thiscall->next;
+ } else {
+ client->waitDispatch = thiscall->next;
+ }
+ break;
+ }
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ VIR_DEBUG("Giving up the buck %p %p", thiscall, client->waitDispatch);
+ virNetClientPassTheBuck(client);
+ return 0;
+ } else {
+ VIR_DEBUG("Giving up the buck %p %p", thiscall, client->waitDispatch);
+ virNetClientPassTheBuck(client);
+ return 1; /* partial send */
+ }
+ }
if (fds[1].revents) {
VIR_DEBUG("Woken up from poll by other thread");
@@ -988,6 +1050,7 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
}
if (ret < 0) {
+ /* XXX what's this dubious errno check doing ? */
if (errno == EWOULDBLOCK)
continue;
virReportSystemError(errno,
@@ -1005,8 +1068,8 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
goto error;
}
- /* Iterate through waiting threads and if
- * any are complete then tell 'em to wakeup
+ /* Iterate through waiting calls and if any are
+ * complete, remove them from the dispatch list..
*/
tmp = client->waitDispatch;
prev = NULL;
@@ -1019,13 +1082,25 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
else
client->waitDispatch = tmp->next;
- /* And wake them up....
- * ...they won't actually wakeup until
+ /*
+ * ...if the call being removed from the list
+ * still has a thread, then wake that thread up,
+ * otherwise free the call. The latter should
+ * only happen for calls without replies.
+ *
+ * ...the threads won't actually wakeup until
* we release our mutex a short while
* later...
*/
- VIR_DEBUG("Waking up sleep %p %p", tmp, client->waitDispatch);
- virCondSignal(&tmp->cond);
+ if (tmp->haveThread) {
+ VIR_DEBUG("Waking up sleep %p %p", tmp, client->waitDispatch);
+ virCondSignal(&tmp->cond);
+ } else {
+ if (tmp->expectReply)
+ VIR_WARN("Got a call expecting a reply but without a waiting thread");
+ ignore_value(virCondDestroy(&tmp->cond));
+ VIR_FREE(tmp);
+ }
} else {
prev = tmp;
}
@@ -1039,13 +1114,8 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
*/
client->waitDispatch = thiscall->next;
VIR_DEBUG("Giving up the buck %p %p", thiscall, client->waitDispatch);
- /* See if someone else is still waiting
- * and if so, then pass the buck ! */
- if (client->waitDispatch) {
- VIR_DEBUG("Passing the buck to %p", client->waitDispatch);
- virCondSignal(&client->waitDispatch->cond);
- }
- return 0;
+ virNetClientPassTheBuck(client);
+ return 2;
}
@@ -1060,16 +1130,21 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
error:
client->waitDispatch = thiscall->next;
VIR_DEBUG("Giving up the buck due to I/O error %p %p", thiscall, client->waitDispatch);
- /* See if someone else is still waiting
- * and if so, then pass the buck ! */
- if (client->waitDispatch) {
- VIR_DEBUG("Passing the buck to %p", client->waitDispatch);
- virCondSignal(&client->waitDispatch->cond);
- }
+ virNetClientPassTheBuck(client);
return -1;
}
+static void
+virNetClientUpdateIOCallback(virNetClientPtr client, bool enabled)
+{
+ int events = 0;
+ if (enabled) {
+ events |= VIR_EVENT_HANDLE_READABLE;
+ }
+ virNetSocketUpdateIOCallback(client->sock, events);
+}
+
/*
* This function sends a message to remote server and awaits a reply
*
@@ -1102,11 +1177,15 @@ error:
* nation are blamed on another, providing an opportunity for war."
*
* NB(5) Don't Panic!
+ *
+ * Returns 2 if fully sent, 1 if partially sent (only for nonBlock==true),
+ * 0 if nothing sent (only for nonBlock==true) and -1 on error
*/
static int virNetClientIO(virNetClientPtr client,
virNetClientCallPtr thiscall)
{
int rv = -1;
+ virNetClientCallPtr tmp;
VIR_DEBUG("Outgoing message prog=%u version=%u serial=%u proc=%d type=%d length=%zu dispatch=%p",
thiscall->msg->header.prog,
@@ -1117,20 +1196,27 @@ static int virNetClientIO(virNetClientPtr client,
thiscall->msg->bufferLength,
client->waitDispatch);
+ /* Trivially detect blocking if someone else has the buck already */
+ if (client->haveTheBuck &&
+ thiscall->nonBlock)
+ return 0;
+
+ /* Stick ourselves on the end of the wait queue */
+ tmp = client->waitDispatch;
+ while (tmp && tmp->next)
+ tmp = tmp->next;
+ if (tmp)
+ tmp->next = thiscall;
+ else
+ client->waitDispatch = thiscall;
+
/* Check to see if another thread is dispatching */
- if (client->waitDispatch) {
- /* Stick ourselves on the end of the wait queue */
- virNetClientCallPtr tmp = client->waitDispatch;
+ if (client->haveTheBuck) {
char ignore = 1;
- while (tmp && tmp->next)
- tmp = tmp->next;
- if (tmp)
- tmp->next = thiscall;
- else
- client->waitDispatch = thiscall;
/* Force other thread to wakeup from poll */
if (safewrite(client->wakeupSendFD, &ignore, sizeof(ignore)) != sizeof(ignore)) {
+ /* Something went wrong, so we need to remove that call we just added */
if (tmp)
tmp->next = NULL;
else
@@ -1143,6 +1229,7 @@ static int virNetClientIO(virNetClientPtr client,
VIR_DEBUG("Going to sleep %p %p", client->waitDispatch, thiscall);
/* Go to sleep while other thread is working... */
if (virCondWait(&thiscall->cond, &client->lock) < 0) {
+ /* Something went wrong, so we need to remove that call we previously added */
if (client->waitDispatch == thiscall) {
client->waitDispatch = thiscall->next;
} else {
@@ -1167,7 +1254,7 @@ static int virNetClientIO(virNetClientPtr client,
* our reply
*/
if (thiscall->mode == VIR_NET_CLIENT_MODE_COMPLETE) {
- rv = 0;
+ rv = 2;
/*
* We avoided catching the buck and our reply is ready !
* We've already had 'thiscall' removed from the list
@@ -1177,12 +1264,10 @@ static int virNetClientIO(virNetClientPtr client,
}
/* Grr, someone passed the buck onto us ... */
-
- } else {
- /* We're first to catch the buck */
- client->waitDispatch = thiscall;
}
+ client->haveTheBuck = true;
+
VIR_DEBUG("We have the buck %p %p", client->waitDispatch, thiscall);
/*
* The buck stops here!
@@ -1198,17 +1283,19 @@ static int virNetClientIO(virNetClientPtr client,
* cause the event loop thread to be blocked on the
* mutex for the duration of the call
*/
- virNetSocketUpdateIOCallback(client->sock, 0);
+ virNetClientUpdateIOCallback(client, false);
virResetLastError();
rv = virNetClientIOEventLoop(client, thiscall);
- virNetSocketUpdateIOCallback(client->sock, VIR_EVENT_HANDLE_READABLE);
+ virNetClientUpdateIOCallback(client, true);
if (rv == 0 &&
virGetLastError())
rv = -1;
+ client->haveTheBuck = false;
+
cleanup:
VIR_DEBUG("All done with our call %p %p %d", client->waitDispatch, thiscall, rv);
return rv;
@@ -1227,7 +1314,7 @@ void virNetClientIncomingEvent(virNetSocketPtr sock,
goto done;
/* This should be impossible, but it doesn't hurt to check */
- if (client->waitDispatch)
+ if (client->haveTheBuck)
goto done;
VIR_DEBUG("Event fired %p %d", sock, events);
@@ -1249,9 +1336,14 @@ done:
}
-int virNetClientSend(virNetClientPtr client,
- virNetMessagePtr msg,
- bool expectReply)
+/*
+ * Returns 2 if fully sent, 1 if partially sent (only for nonBlock==true),
+ * 0 if nothing sent (only for nonBlock==true) and -1 on error
+ */
+static int virNetClientSendInternal(virNetClientPtr client,
+ virNetMessagePtr msg,
+ bool expectReply,
+ bool nonBlock)
{
virNetClientCallPtr call;
int ret = -1;
@@ -1270,6 +1362,12 @@ int virNetClientSend(virNetClientPtr client,
return -1;
}
+ if (expectReply && nonBlock) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Attempt to send an non-blocking message with a synchronous reply"));
+ return -1;
+ }
+
if (VIR_ALLOC(call) < 0) {
virReportOOMError();
return -1;
@@ -1290,12 +1388,75 @@ int virNetClientSend(virNetClientPtr client,
call->mode = VIR_NET_CLIENT_MODE_WAIT_RX;
call->msg = msg;
call->expectReply = expectReply;
+ call->nonBlock = nonBlock;
+ call->haveThread = true;
ret = virNetClientIO(client, call);
cleanup:
- ignore_value(virCondDestroy(&call->cond));
- VIR_FREE(call);
+ /* If partially sent, then the call is still on the dispatch queue */
+ if (ret == 1) {
+ call->haveThread = false;
+ } else {
+ ignore_value(virCondDestroy(&call->cond));
+ VIR_FREE(call);
+ }
virNetClientUnlock(client);
return ret;
}
+
+
+/*
+ * @msg: a message allocated on heap or stack
+ *
+ * Send a message synchronously, and wait for the reply synchronously
+ *
+ * The caller is responsible for free'ing @msg if it was allocated
+ * on the heap
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int virNetClientSend(virNetClientPtr client,
+ virNetMessagePtr msg)
+{
+ int ret = virNetClientSendInternal(client, msg, true, false);
+ if (ret < 0)
+ return -1;
+ return 0;
+}
+
+
+/*
+ * @msg: a message allocated on heap or stack
+ *
+ * Send a message synchronously, without any reply
+ *
+ * The caller is responsible for free'ing @msg if it was allocated
+ * on the heap
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int virNetClientSendNoReply(virNetClientPtr client,
+ virNetMessagePtr msg)
+{
+ int ret = virNetClientSendInternal(client, msg, false, false);
+ if (ret < 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * @msg: a message allocated on the heap.
+ *
+ * Send a message asynchronously, without any reply
+ *
+ * The caller is responsible for free'ing @msg, *except* if
+ * this method returns -1.
+ *
+ * Returns 2 on full send, 1 on partial send, 0 on no send, -1 on error
+ */
+int virNetClientSendNonBlock(virNetClientPtr client,
+ virNetMessagePtr msg)
+{
+ return virNetClientSendInternal(client, msg, false, true);
+}
diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h
index fb679e8..d3c112a 100644
--- a/src/rpc/virnetclient.h
+++ b/src/rpc/virnetclient.h
@@ -67,9 +67,17 @@ int virNetClientAddStream(virNetClientPtr client,
void virNetClientRemoveStream(virNetClientPtr client,
virNetClientStreamPtr st);
+/* Send a message and wait for reply */
int virNetClientSend(virNetClientPtr client,
- virNetMessagePtr msg,
- bool expectReply);
+ virNetMessagePtr msg);
+
+/* Send a message without needing a reply */
+int virNetClientSendNoReply(virNetClientPtr client,
+ virNetMessagePtr msg);
+
+/* Send a message without needing a reply, and don't block on I/O */
+int virNetClientSendNonBlock(virNetClientPtr client,
+ virNetMessagePtr msg);
# ifdef HAVE_SASL
void virNetClientSetSASLSession(virNetClientPtr client,
diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c
index 36e2384..cb02a25 100644
--- a/src/rpc/virnetclientprogram.c
+++ b/src/rpc/virnetclientprogram.c
@@ -327,7 +327,7 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
if (virNetMessageEncodePayload(msg, args_filter, args) < 0)
goto error;
- if (virNetClientSend(client, msg, true) < 0)
+ if (virNetClientSend(client, msg) < 0)
goto error;
/* None of these 3 should ever happen here, because
diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c
index 7e2d9ae..309d48d 100644
--- a/src/rpc/virnetclientstream.c
+++ b/src/rpc/virnetclientstream.c
@@ -361,8 +361,13 @@ int virNetClientStreamSendPacket(virNetClientStreamPtr st,
wantReply = true;
}
- if (virNetClientSend(client, msg, wantReply) < 0)
- goto error;
+ if (wantReply) {
+ if (virNetClientSend(client, msg) < 0)
+ goto error;
+ } else {
+ if (virNetClientSendNoReply(client, msg) < 0)
+ goto error;
+ }
virNetMessageFree(msg);
@@ -407,7 +412,7 @@ int virNetClientStreamRecvPacket(virNetClientStreamPtr st,
VIR_DEBUG("Dummy packet to wait for stream data");
virMutexUnlock(&st->lock);
- ret = virNetClientSend(client, msg, true);
+ ret = virNetClientSend(client, msg);
virMutexLock(&st->lock);
virNetMessageFree(msg);
--
1.7.6.4
13 years
[libvirt] [PATCH] Don't return a fatal error if receiving unexpected stream data
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Due to the asynchronous nature of streams, we might continue to
receive some stream packets from the server even after we have
shutdown the stream on the client side. These should be discarded
silently, rather than raising an error in the RPC layer.
* src/rpc/virnetclient.c: Discard stream data silently
---
src/rpc/virnetclient.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 4b7d4a9..4cbdf55 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -621,7 +621,9 @@ static int virNetClientCallDispatchStream(virNetClientPtr client)
VIR_DEBUG("No stream found for packet with prog=%d vers=%d serial=%u proc=%u",
client->msg.header.prog, client->msg.header.vers,
client->msg.header.serial, client->msg.header.proc);
- return -1;
+ /* Don't return -1, because we expect to see further stream packets
+ * after we've shut it down sometimes */
+ return 0;
}
/* Finish/Abort are synchronous, so also see if there's an
--
1.7.6.4
13 years
[libvirt] [PATCH] lxc: plug memory leak
by ajia@redhat.com
From: Alex Jia <ajia(a)redhat.com>
Detected by Coverity. Leak introduced in commit 0f31f7b.
* src/lxc/lxc_driver.c: Clean up on failure.
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
src/lxc/lxc_driver.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 37092bc..a1d0a7c 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1850,6 +1850,7 @@ cleanup:
}
for (i = 0 ; i < nttyFDs ; i++)
VIR_FORCE_CLOSE(ttyFDs[i]);
+ VIR_FREE(ttyFDs);
VIR_FORCE_CLOSE(handshakefds[0]);
VIR_FORCE_CLOSE(handshakefds[1]);
VIR_FREE(logfile);
--
1.7.1
13 years
[libvirt] [PATCH] lxc: plug memory leak
by ajia@redhat.com
From: Alex Jia <ajia(a)redhat.com>
Detected by Coverity. Leak introduced in commit 9d201a5.
* src/lxc/lxc_driver.c: Clean up on failure.
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
src/lxc/lxc_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 37092bc..295fd6f 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1856,7 +1856,7 @@ cleanup:
if (err) {
virSetError(err);
- virResetError(err);
+ virFreeError(err);
}
return rc;
--
1.7.1
13 years