[libvirt] [PATCH] libvirt-tck: Skip Test when no security model is in use
by Guido Günther
Hi,
if I'm reading this test correctly it's supposed to fail without a
security model at work.
The file images are always readable/writeable to the libvirt user and
group without one.
Cheers,
-- Guido
---
scripts/qemu/205-qcow2-double-backing-file.t | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/scripts/qemu/205-qcow2-double-backing-file.t b/scripts/qemu/205-qcow2-double-backing-file.t
index 7ae278d..d3a5e33 100644
--- a/scripts/qemu/205-qcow2-double-backing-file.t
+++ b/scripts/qemu/205-qcow2-double-backing-file.t
@@ -52,17 +52,22 @@ my $conn = eval { $tck->setup(); };
BAIL_OUT "failed to setup test harness: $@" if $@;
END { $tck->cleanup if $tck; }
+my $info;
+eval {
+ $info = $conn->get_node_security_model();
+};
+
SKIP: {
skip "Only relevant to QEMU driver", 26 unless $conn->get_type() eq "QEMU";
skip "Only relevant when run as root", 26 unless $< == 0;
skip "Only relevant for system driver", 26 unless
$conn->get_uri() =~ m/system/;
-
+ skip "Only relevant when using a security model", 26 unless
+ $info && $info->{model};
my $xml = $tck->generic_pool("dir")
->mode("0755")->as_xml;
-
diag "Defining transient storage pool $xml";
my $pool;
ok_pool(sub { $pool = $conn->define_storage_pool($xml) }, "define transient storage pool");
--
1.7.7
13 years
[libvirt] [PATCH] Add ability to managed save libvirt domains
by Pavel Odintsov
---
src/libvirt-php.c | 21 +++++++++++++++++++++
src/libvirt-php.h | 1 +
2 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/src/libvirt-php.c b/src/libvirt-php.c
index f590595..1c39e31 100644
--- a/src/libvirt-php.c
+++ b/src/libvirt-php.c
@@ -91,6 +91,7 @@ static function_entry libvirt_functions[] = {
PHP_FE(libvirt_domain_core_dump, NULL)
PHP_FE(libvirt_domain_shutdown, NULL)
PHP_FE(libvirt_domain_suspend, NULL)
+ PHP_FE(libvirt_domain_managedsave, NULL)
PHP_FE(libvirt_domain_undefine, NULL)
PHP_FE(libvirt_domain_reboot, NULL)
PHP_FE(libvirt_domain_define_xml, NULL)
@@ -3625,6 +3626,26 @@ PHP_FUNCTION(libvirt_domain_suspend)
}
/*
+ Function name: libvirt_domain_managedsave
+ Since version: 0.4.1(-1)
+ Description: Function is used to managed save the domain (domain was unloaded from memory and its state was saved to disk) identified by it's resource
+ Arguments: @res [resource]: libvirt domain resource, e.g. from libvirt_domain_lookup_by_*()
+ Returns: TRUE for success, FALSE on error
+*/
+PHP_FUNCTION(libvirt_domain_managedsave)
+{
+ php_libvirt_domain *domain=NULL;
+ zval *zdomain;
+ int retval;
+
+ GET_DOMAIN_FROM_ARGS("r",&zdomain);
+ retval=virDomainManagedSave(domain->domain, 0);
+ DPRINTF("%s: virDomainManagedSave(%p) returned %d\n", PHPFUNC, domain->domain, retval);
+ if (retval != 0) RETURN_FALSE;
+ RETURN_TRUE;
+}
+
+/*
Function name: libvirt_domain_undefine
Since version: 0.4.1(-1)
Description: Function is used to undefine the domain identified by it's resource
diff --git a/src/libvirt-php.h b/src/libvirt-php.h
index 2addae2..8a3f4ff 100644
--- a/src/libvirt-php.h
+++ b/src/libvirt-php.h
@@ -237,6 +237,7 @@ PHP_FUNCTION(libvirt_domain_resume);
PHP_FUNCTION(libvirt_domain_core_dump);
PHP_FUNCTION(libvirt_domain_shutdown);
PHP_FUNCTION(libvirt_domain_suspend);
+PHP_FUNCTION(libvirt_domain_managedsave);
PHP_FUNCTION(libvirt_domain_undefine);
PHP_FUNCTION(libvirt_domain_reboot);
PHP_FUNCTION(libvirt_domain_define_xml);
--
1.7.2.5
13 years
[libvirt] [PATCH] qemu: drop driver lock around sleep
by Eric Blake
qemu/THREADS.txt is explicit that the driver lock must not be
held for long lengths of time, as it blocks all attempts to
manage any other vms on the same connection. We were violating
this by sleep()ing while waiting for a qemu child process to
finish execution during actions such as destroy.
* src/qemu/qemu_process.h (qemuProcessKill): Alter signature.
* src/qemu/qemu_process.c (qemuProcessKill): Add parameter.
(qemuProcessFakeReboot, qemuProcessShutdownOrReboot)
(qemuProcessStop): Update callers.
* src/qemu/qemu_driver.c (qemuDomainDestroyFlags): Likewise.
---
Without this patch, problems in halting one domain could lock
out actions on all other domains for more than 3 seconds, which
is awfully long.
This doesn't solve all the problems - it is still possible to
have a stuck NFS server being the reason for difficulties in
stopping a domain, such as an lstat() call while attempting to
relabel file systems, and those calls are still done while
the driver lock is held; but I'll be submitting further patches
as I try and reduce the critical section sizes.
I'm not sure whether this qualifies for 0.9.7 or should wait
for post-release.
src/qemu/qemu_driver.c | 2 +-
src/qemu/qemu_process.c | 35 ++++++++++++++++++++++++++++-------
src/qemu/qemu_process.h | 3 ++-
3 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 118197a..2a152e8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1692,7 +1692,7 @@ qemuDomainDestroyFlags(virDomainPtr dom,
* can kill the process even if a job is active. Killing
* it now means the job will be released
*/
- qemuProcessKill(vm, false);
+ qemuProcessKill(driver, vm, false);
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
goto cleanup;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 2882ef8..6867d26 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -419,7 +419,7 @@ endjob:
cleanup:
if (vm) {
if (ret == -1)
- qemuProcessKill(vm, false);
+ qemuProcessKill(driver, vm, false);
if (virDomainObjUnref(vm) > 0)
virDomainObjUnlock(vm);
}
@@ -450,12 +450,12 @@ qemuProcessShutdownOrReboot(virDomainObjPtr vm)
qemuProcessFakeReboot,
vm) < 0) {
VIR_ERROR(_("Failed to create reboot thread, killing domain"));
- qemuProcessKill(vm, true);
+ qemuProcessKill(qemu_driver, vm, true);
/* Safe to ignore value since ref count was incremented above */
ignore_value(virDomainObjUnref(vm));
}
} else {
- qemuProcessKill(vm, true);
+ qemuProcessKill(qemu_driver, vm, true);
}
}
@@ -3249,17 +3249,26 @@ cleanup:
}
-void qemuProcessKill(virDomainObjPtr vm, bool gracefully)
+/* Called while owning the vm lock, but not necessarily a job on the
+ * vm. This function returns immediately if gracefully is true,
+ * otherwise it may block while waiting for the qemu process. If
+ * driver is non-NULL, then also drop the driver lock before sleeping
+ * and re-acquire before returning. */
+void qemuProcessKill(struct qemud_driver *driver, virDomainObjPtr vm,
+ bool gracefully)
{
int i;
- VIR_DEBUG("vm=%s pid=%d gracefully=%d",
- vm->def->name, vm->pid, gracefully);
+ VIR_DEBUG("driver=%p vm=%s pid=%d gracefully=%d",
+ driver, vm->def->name, vm->pid, gracefully);
if (!virDomainObjIsActive(vm)) {
VIR_DEBUG("VM '%s' not active", vm->def->name);
return;
}
+ if (driver && !gracefully)
+ qemuDriverUnlock(driver);
+
/* This loop sends SIGTERM, then waits a few iterations
* (1.6 seconds) to see if it dies. If still alive then
* it does SIGKILL, and waits a few more iterations (1.6
@@ -3288,6 +3297,18 @@ void qemuProcessKill(virDomainObjPtr vm, bool gracefully)
usleep(200 * 1000);
}
+
+ if (driver && !gracefully) {
+ /* Must hold extra reference while dropping vm lock, since we
+ * do not necessarily have an active job to guarantee a
+ * reference. */
+ virDomainObjRef(vm);
+ virDomainObjUnlock(vm);
+ qemuDriverLock(driver);
+ virDomainObjLock(vm);
+ /* Safe to ignore value since ref count was incremented above */
+ ignore_value(virDomainObjUnref(vm));
+ }
}
@@ -3370,7 +3391,7 @@ void qemuProcessStop(struct qemud_driver *driver,
}
/* shut it off for sure */
- qemuProcessKill(vm, false);
+ qemuProcessKill(driver, vm, false);
/* Stop autodestroy in case guest is restarted */
qemuProcessAutoDestroyRemove(driver, vm);
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index ef422c4..19ed8a1 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -68,7 +68,8 @@ int qemuProcessAttach(virConnectPtr conn,
virDomainChrSourceDefPtr monConfig,
bool monJSON);
-void qemuProcessKill(virDomainObjPtr vm, bool gracefully);
+void qemuProcessKill(struct qemud_driver *driver, virDomainObjPtr vm,
+ bool gracefully);
int qemuProcessAutoDestroyInit(struct qemud_driver *driver);
void qemuProcessAutoDestroyRun(struct qemud_driver *driver,
--
1.7.4.4
13 years
[libvirt] [PATCH 0/7] Allow multiple console devices for each guest
by Daniel P. Berrange
The current XML schema only allows for a single <console> element
per guest. Many hypervisors support multiple paravirt consoles,
and it'd be desirable to support that. This series does just that,
enabling multiple consoles for UML, QEMU and LXC
13 years
[libvirt] [PATCHv6 0/5] expose per-device blkio weight tuning, via string param
by Eric Blake
This is v6 of Hu's original proposal:
v1: https://www.redhat.com/archives/libvir-list/2011-September/msg00334.html
v4: https://www.redhat.com/archives/libvir-list/2011-October/msg00444.html
v5: https://www.redhat.com/archives/libvir-list/2011-November/msg00060.html
Patches 1-3 are solid in my testing. When I first started working
on these patches, I was thinking it would be worth having
VIR_TYPED_PARAM_STRING in 0.9.7; however, now that I've spent
longer on it, I'm reluctant to push this new virTypedParameter API
without at least one other API that takes advantage of a typed string.
I tested 1-3 by using patches 4 and 5, using all 4 combinations
of pre- and post-patch clients and servers. If either (or both)
sides were old, then behavior is unchanged from 0.9.6 (no strings
are present, a new client won't confuse an old server, a new
server won't confuse an old client, and all non-string parameters
are still passed in all cases); if both sides are new, then
the string passing works as designed.
Patch 4 is close to feature-complete, and would be the first API to
take advantage of patches 1-3, but it is pointless to apply it
without at least one driver implementation. Also, it has a user
interface issue, in that '/path/to/dev1,weight;/path/to/dev2,weight'
is awkward to type in a virsh command line; it might be nicer if
if we used the string '/path/to/dev1,weight,/path/to/dev2,weight'
instead, but that would mean some further parsing alterations.
Note that in patch 4, I renamed the virsh option to
'virsh blkiotune --device-weight', in part because having both
'--weight-device' and '--weight' would interfere with my (future)
plans to make virsh do unambiguous option prefix parsing, and in
part because the XML is laid out with device as the primary name,
with weight as a sub-feature of each device (just because cgroups
named things backwards doesn't mean that we have to repeat that
mistake).
Patch 5 is broken. I've already spent too long on this series, so
I'm hoping Hu can resume ownership of this series and post a working
v7 that resolves my complaints. More details in that particular
patch message; but the short summary is that 'virsh blkiotune --live'
and 'virsh blkiotune --config' must give identically formatted
output.
Eric Blake (4):
API: add VIR_TYPED_PARAM_STRING
API: remote support for VIR_TYPED_PARAM_STRING
API: add trivial qemu support for VIR_TYPED_PARAM_STRING
blkiotune: add interface for blkiotune.device_weight
Hu Tao (1):
blkiotune: add qemu support for blkiotune.device_weight
daemon/remote.c | 88 ++++++++++++-----
docs/formatdomain.html.in | 29 +++++-
docs/schemas/domaincommon.rng | 12 +++
include/libvirt/libvirt.h.in | 42 ++++++++-
src/conf/domain_conf.c | 130 ++++++++++++++++++++++++-
src/conf/domain_conf.h | 17 ++++
src/libvirt.c | 92 +++++++++++++++---
src/libvirt_internal.h | 9 ++-
src/libvirt_private.syms | 3 +
src/qemu/qemu_cgroup.c | 22 ++++
src/qemu/qemu_driver.c | 213 +++++++++++++++++++++++++++++++++++++++--
src/remote/remote_driver.c | 28 +++++-
src/remote/remote_protocol.x | 2 +
src/remote_protocol-structs | 2 +
src/rpc/gendispatch.pl | 3 +-
src/util/cgroup.c | 33 +++++++
src/util/cgroup.h | 4 +
src/util/util.c | 14 +++
src/util/util.h | 2 +
tools/virsh.c | 32 ++++++-
tools/virsh.pod | 6 +-
21 files changed, 720 insertions(+), 63 deletions(-)
--
1.7.4.4
13 years
[libvirt] [PATCH 1/2] build: fix linking on BSD
by Eric Blake
While building on FreeBSD (and after fixing a ptsname_r link error),
I got this failure:
./.libs/libvirt_util.a(libvirt_util_la-threads.o)(.text+0x240): In function `virThreadCreate':
util/threads-pthread.c:185: undefined reference to `pthread_create'
It turns out that gnulib used only pthread_join for LIB_PTHREAD,
but on FreeBSD, libc provides that (as a stub function); whereas
the more complex pthread_create really does require -pthread,
which gnulib tracked under [LT]LIBMULTITHREAD.
* configure.ac (LIBS): Check LIBMULTITHREAD alongside LIB_PTHREAD.
* src/Makefile.am (THREAD_LIBS): New variable.
(libvirt_util_la_LIBADD, libvirt_lxc_LDADD): Use it.
---
Pushing under the build-breaker rule. However, the build is still
broken unless we also push:
https://www.redhat.com/archives/libvir-list/2011-November/msg00210.html
configure.ac | 4 ++--
src/Makefile.am | 6 ++++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5753c08..8754f18 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,9 +141,9 @@ AC_CHECK_FUNCS_ONCE([cfmakeraw geteuid getgid getgrnam_r getmntent_r \
dnl Availability of pthread functions (if missing, win32 threading is
dnl assumed). Because of $LIB_PTHREAD, we cannot use AC_CHECK_FUNCS_ONCE.
-dnl LIB_PTHREAD was set during gl_INIT by gnulib.
+dnl LIB_PTHREAD and LIBMULTITHREAD were set during gl_INIT by gnulib.
old_LIBS=$LIBS
-LIBS="$LIBS $LIB_PTHREAD"
+LIBS="$LIBS $LIB_PTHREAD $LIBMULTITHREAD"
AC_CHECK_FUNCS([pthread_mutexattr_init])
LIBS=$old_libs
diff --git a/src/Makefile.am b/src/Makefile.am
index bf26b19..c419c94 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,6 +29,8 @@ CLEANFILES =
DISTCLEANFILES =
MAINTAINERCLEANFILES =
+THREAD_LIBS = $(LIB_PTHREAD) $(LTLIBMULTITHREAD)
+
if WITH_NETWORK
UUID=$(shell uuidgen 2>/dev/null)
endif
@@ -548,7 +550,7 @@ libvirt_util_la_SOURCES = \
libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
$(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS)
libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
- $(LIB_PTHREAD) $(AUDIT_LIBS) $(DEVMAPPER_LIBS)
+ $(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS)
noinst_LTLIBRARIES += libvirt_conf.la
@@ -1481,7 +1483,7 @@ libvirt_lxc_SOURCES = \
$(NWFILTER_PARAM_CONF_SOURCES)
libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS)
libvirt_lxc_LDADD = $(CAPNG_LIBS) $(YAJL_LIBS) \
- $(LIBXML_LIBS) $(NUMACTL_LIBS) $(LIB_PTHREAD) \
+ $(LIBXML_LIBS) $(NUMACTL_LIBS) $(THREAD_LIBS) \
$(LIBNL_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \
../gnulib/lib/libgnu.la
if WITH_DTRACE
--
1.7.4.4
13 years
[libvirt] [PATCH] Fix sending/receiving of FDs when stream returns EAGAIN
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The code calling sendfd/recvfd was mistakenly assuming those
calls would never block. They can in fact return EAGAIN and
this is causing us to drop the client connection when blocking
ocurrs while sending/receiving FDs.
Fixing this is a little hairy on the incoming side, since at
the point where we see the EAGAIN, we already thought we had
finished receiving all data for the packet. So we play a little
trick to reset bufferOffset again and go back into polling for
more data.
* src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Update
virNetSocketSendFD/RecvFD to return 0 on EAGAIN, or 1
on success
* src/rpc/virnetclient.c: Move decoding of header & fds
out of virNetClientCallDispatch and into virNetClientIOHandleInput.
Handling blocking when sending/receiving FDs
* src/rpc/virnetmessage.h: Add a 'donefds' field to track
how many FDs we've sent / received
* src/rpc/virnetserverclient.c: Handling blocking when
sending/receiving FDs
---
src/rpc/virnetclient.c | 79 ++++++++++++++++++++++++++++--------------
src/rpc/virnetmessage.h | 1 +
src/rpc/virnetserverclient.c | 62 ++++++++++++++++++++++++---------
src/rpc/virnetsocket.c | 34 +++++++++++++-----
src/rpc/virnetsocket.h | 2 +-
5 files changed, 125 insertions(+), 53 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 2b5f67c..4b7d4a9 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -694,10 +694,6 @@ static int virNetClientCallDispatchStream(virNetClientPtr client)
static int
virNetClientCallDispatch(virNetClientPtr client)
{
- size_t i;
- if (virNetMessageDecodeHeader(&client->msg) < 0)
- return -1;
-
PROBE(RPC_CLIENT_MSG_RX,
"client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u",
client, client->msg.bufferLength,
@@ -706,15 +702,7 @@ virNetClientCallDispatch(virNetClientPtr client)
switch (client->msg.header.type) {
case VIR_NET_REPLY: /* Normal RPC replies */
- return virNetClientCallDispatchReply(client);
-
case VIR_NET_REPLY_WITH_FDS: /* Normal RPC replies with FDs */
- if (virNetMessageDecodeNumFDs(&client->msg) < 0)
- return -1;
- for (i = 0 ; i < client->msg.nfds ; i++) {
- if ((client->msg.fds[i] = virNetSocketRecvFD(client->sock)) < 0)
- return -1;
- }
return virNetClientCallDispatchReply(client);
case VIR_NET_MESSAGE: /* Async notifications */
@@ -737,22 +725,29 @@ static ssize_t
virNetClientIOWriteMessage(virNetClientPtr client,
virNetClientCallPtr thecall)
{
- ssize_t ret;
+ ssize_t ret = 0;
- ret = virNetSocketWrite(client->sock,
- thecall->msg->buffer + thecall->msg->bufferOffset,
- thecall->msg->bufferLength - thecall->msg->bufferOffset);
- if (ret <= 0)
- return ret;
+ if (thecall->msg->bufferOffset < thecall->msg->bufferLength) {
+ ret = virNetSocketWrite(client->sock,
+ thecall->msg->buffer + thecall->msg->bufferOffset,
+ thecall->msg->bufferLength - thecall->msg->bufferOffset);
+ if (ret <= 0)
+ return ret;
- thecall->msg->bufferOffset += ret;
+ thecall->msg->bufferOffset += ret;
+ }
if (thecall->msg->bufferOffset == thecall->msg->bufferLength) {
size_t i;
- for (i = 0 ; i < thecall->msg->nfds ; i++) {
- if (virNetSocketSendFD(client->sock, thecall->msg->fds[i]) < 0)
+ for (i = thecall->msg->donefds ; i < thecall->msg->nfds ; i++) {
+ int rv;
+ if ((rv = virNetSocketSendFD(client->sock, thecall->msg->fds[i])) < 0)
return -1;
+ if (rv == 0) /* Blocking */
+ return 0;
+ thecall->msg->donefds++;
}
+ thecall->msg->donefds = 0;
thecall->msg->bufferOffset = thecall->msg->bufferLength = 0;
if (thecall->expectReply)
thecall->mode = VIR_NET_CLIENT_MODE_WAIT_RX;
@@ -821,12 +816,16 @@ virNetClientIOHandleInput(virNetClientPtr client)
* EAGAIN
*/
for (;;) {
- ssize_t ret = virNetClientIOReadMessage(client);
+ ssize_t ret;
- if (ret < 0)
- return -1;
- if (ret == 0)
- return 0; /* Blocking on read */
+ if (client->msg.nfds == 0) {
+ ret = virNetClientIOReadMessage(client);
+
+ if (ret < 0)
+ return -1;
+ if (ret == 0)
+ return 0; /* Blocking on read */
+ }
/* Check for completion of our goal */
if (client->msg.bufferOffset == client->msg.bufferLength) {
@@ -842,6 +841,33 @@ virNetClientIOHandleInput(virNetClientPtr client)
* next iteration.
*/
} else {
+ if (virNetMessageDecodeHeader(&client->msg) < 0)
+ return -1;
+
+ if (client->msg.header.type == VIR_NET_REPLY_WITH_FDS) {
+ size_t i;
+ if (virNetMessageDecodeNumFDs(&client->msg) < 0)
+ return -1;
+
+ for (i = client->msg.donefds ; i < client->msg.nfds ; i++) {
+ int rv;
+ if ((rv = virNetSocketRecvFD(client->sock, &(client->msg.fds[i]))) < 0)
+ return -1;
+ if (rv == 0) /* Blocking */
+ break;
+ client->msg.donefds++;
+ }
+
+ if (client->msg.donefds < client->msg.nfds) {
+ /* Because DecodeHeader/NumFDs reset bufferOffset, we
+ * put it back to what it was, so everything works
+ * again next time we run this method
+ */
+ client->msg.bufferOffset = client->msg.bufferLength;
+ return 0; /* Blocking on more fds */
+ }
+ }
+
ret = virNetClientCallDispatch(client);
client->msg.bufferOffset = client->msg.bufferLength = 0;
/*
@@ -1257,6 +1283,7 @@ int virNetClientSend(virNetClientPtr client,
goto cleanup;
}
+ msg->donefds = 0;
if (msg->bufferLength)
call->mode = VIR_NET_CLIENT_MODE_WAIT_TX;
else
diff --git a/src/rpc/virnetmessage.h b/src/rpc/virnetmessage.h
index ad63409..c54e7c6 100644
--- a/src/rpc/virnetmessage.h
+++ b/src/rpc/virnetmessage.h
@@ -48,6 +48,7 @@ struct _virNetMessage {
size_t nfds;
int *fds;
+ size_t donefds;
virNetMessagePtr next;
};
diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
index 2f5ae8f..cf97b58 100644
--- a/src/rpc/virnetserverclient.c
+++ b/src/rpc/virnetserverclient.c
@@ -771,9 +771,11 @@ static ssize_t virNetServerClientRead(virNetServerClientPtr client)
static void virNetServerClientDispatchRead(virNetServerClientPtr client)
{
readmore:
- if (virNetServerClientRead(client) < 0) {
- client->wantClose = true;
- return; /* Error */
+ if (client->rx->nfds == 0) {
+ if (virNetServerClientRead(client) < 0) {
+ client->wantClose = true;
+ return; /* Error */
+ }
}
if (client->rx->bufferOffset < client->rx->bufferLength)
@@ -794,7 +796,7 @@ readmore:
goto readmore;
} else {
/* Grab the completed message */
- virNetMessagePtr msg = virNetMessageQueueServe(&client->rx);
+ virNetMessagePtr msg = client->rx;
virNetServerClientFilterPtr filter;
size_t i;
@@ -805,20 +807,40 @@ readmore:
return;
}
+ /* Now figure out if we need to read more data to get some
+ * file descriptors */
if (msg->header.type == VIR_NET_CALL_WITH_FDS &&
virNetMessageDecodeNumFDs(msg) < 0) {
virNetMessageFree(msg);
client->wantClose = true;
- return;
+ return; /* Error */
}
- for (i = 0 ; i < msg->nfds ; i++) {
- if ((msg->fds[i] = virNetSocketRecvFD(client->sock)) < 0) {
+
+ /* Try getting the file descriptors (may fail if blocking) */
+ for (i = msg->donefds ; i < msg->nfds ; i++) {
+ int rv;
+ if ((rv = virNetSocketRecvFD(client->sock, &(msg->fds[i]))) < 0) {
virNetMessageFree(msg);
client->wantClose = true;
return;
}
+ if (rv == 0) /* Blocking */
+ break;
+ msg->donefds++;
+ }
+
+ /* Need to poll() until FDs arrive */
+ if (msg->donefds < msg->nfds) {
+ /* Because DecodeHeader/NumFDs reset bufferOffset, we
+ * put it back to what it was, so everything works
+ * again next time we run this method
+ */
+ client->rx->bufferOffset = client->rx->bufferLength;
+ return;
}
+ /* Definitely finished reading, so remove from queue */
+ virNetMessageQueueServe(&client->rx);
PROBE(RPC_SERVER_CLIENT_MSG_RX,
"client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u",
client, msg->bufferLength,
@@ -912,25 +934,30 @@ static void
virNetServerClientDispatchWrite(virNetServerClientPtr client)
{
while (client->tx) {
- ssize_t ret;
-
- ret = virNetServerClientWrite(client);
- if (ret < 0) {
- client->wantClose = true;
- return;
+ if (client->tx->bufferOffset < client->tx->bufferLength) {
+ ssize_t ret;
+ ret = virNetServerClientWrite(client);
+ if (ret < 0) {
+ client->wantClose = true;
+ return;
+ }
+ if (ret == 0)
+ return; /* Would block on write EAGAIN */
}
- if (ret == 0)
- return; /* Would block on write EAGAIN */
if (client->tx->bufferOffset == client->tx->bufferLength) {
virNetMessagePtr msg;
size_t i;
- for (i = 0 ; i < client->tx->nfds ; i++) {
- if (virNetSocketSendFD(client->sock, client->tx->fds[i]) < 0) {
+ for (i = client->tx->donefds ; i < client->tx->nfds ; i++) {
+ int rv;
+ if ((rv = virNetSocketSendFD(client->sock, client->tx->fds[i])) < 0) {
client->wantClose = true;
return;
}
+ if (rv == 0) /* Blocking */
+ return;
+ client->tx->donefds++;
}
#if HAVE_SASL
@@ -1041,6 +1068,7 @@ int virNetServerClientSendMessage(virNetServerClientPtr client,
msg->bufferLength, msg->bufferOffset);
virNetServerClientLock(client);
+ msg->donefds = 0;
if (client->sock && !client->wantClose) {
PROBE(RPC_SERVER_CLIENT_MSG_TX_QUEUE,
"client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u",
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index d832c53..4517d16 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -1142,6 +1142,9 @@ ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len)
}
+/*
+ * Returns 1 if an FD was sent, 0 if it would block, -1 on error
+ */
int virNetSocketSendFD(virNetSocketPtr sock, int fd)
{
int ret = -1;
@@ -1154,12 +1157,15 @@ int virNetSocketSendFD(virNetSocketPtr sock, int fd)
PROBE(RPC_SOCKET_SEND_FD,
"sock=%p fd=%d", sock, fd);
if (sendfd(sock->fd, fd) < 0) {
- virReportSystemError(errno,
- _("Failed to send file descriptor %d"),
- fd);
+ if (errno == EAGAIN)
+ ret = 0;
+ else
+ virReportSystemError(errno,
+ _("Failed to send file descriptor %d"),
+ fd);
goto cleanup;
}
- ret = 0;
+ ret = 1;
cleanup:
virMutexUnlock(&sock->lock);
@@ -1167,9 +1173,15 @@ cleanup:
}
-int virNetSocketRecvFD(virNetSocketPtr sock)
+/*
+ * Returns 1 if an FD was read, 0 if it would block, -1 on error
+ */
+int virNetSocketRecvFD(virNetSocketPtr sock, int *fd)
{
int ret = -1;
+
+ *fd = -1;
+
if (!virNetSocketHasPassFD(sock)) {
virNetError(VIR_ERR_INTERNAL_ERROR,
_("Receiving file descriptors is not supported on this socket"));
@@ -1177,13 +1189,17 @@ int virNetSocketRecvFD(virNetSocketPtr sock)
}
virMutexLock(&sock->lock);
- if ((ret = recvfd(sock->fd, O_CLOEXEC)) < 0) {
- virReportSystemError(errno, "%s",
- _("Failed to recv file descriptor"));
+ if ((*fd = recvfd(sock->fd, O_CLOEXEC)) < 0) {
+ if (errno == EAGAIN)
+ ret = 0;
+ else
+ virReportSystemError(errno, "%s",
+ _("Failed to recv file descriptor"));
goto cleanup;
}
PROBE(RPC_SOCKET_RECV_FD,
- "sock=%p fd=%d", sock, ret);
+ "sock=%p fd=%d", sock, *fd);
+ ret = 1;
cleanup:
virMutexUnlock(&sock->lock);
diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h
index 13cbb14..e444aef 100644
--- a/src/rpc/virnetsocket.h
+++ b/src/rpc/virnetsocket.h
@@ -97,7 +97,7 @@ ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len);
ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len);
int virNetSocketSendFD(virNetSocketPtr sock, int fd);
-int virNetSocketRecvFD(virNetSocketPtr sock);
+int virNetSocketRecvFD(virNetSocketPtr sock, int *fd);
void virNetSocketSetTLSSession(virNetSocketPtr sock,
virNetTLSSessionPtr sess);
--
1.7.6.4
13 years
[libvirt] [PATCH] remote: fix mingw32 build
by Laine Stump
tty is initialized, and later set in code that is compiled for all
platforms, but is only used in a section that's inside #ifndef WIN32.
---
src/remote/remote_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index ea7fb24..f3b8ad5 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -377,7 +377,7 @@ doRemoteOpen (virConnectPtr conn,
*/
char *name = NULL, *command = NULL, *sockname = NULL, *netcat = NULL;
char *port = NULL, *authtype = NULL, *username = NULL;
- bool sanity = true, verify = true, tty = true;
+ bool sanity = true, verify = true, tty ATTRIBUTE_UNUSED = true;
char *pkipath = NULL, *keyfile = NULL;
/* Return code from this function, and the private data. */
--
1.7.7
13 years
[libvirt] [PATCH] lxc: avoid use-after-free
by Eric Blake
I got this weird failure:
error: Failed to start domain simple
error: internal error cannot mix caller fds with blocking execution
and tracked it down to a use-after-free - virCommandSetOutputFD
was storing the address of a stack-local variable, which then
went out of scope before the virCommandRun that dereferenced it.
Bug introduced in commit 451cfd05 (0.9.2).
* src/lxc/lxc_driver.c (lxcBuildControllerCmd): Move log fd
registration...
(lxcVmStart): ...to caller.
---
I have no idea how danpb got so lucky in being able to test
recent lxc addtions, given the fact that booting an LXC domain
has basically been broken for several months now, depending on
whether the compiler happened to smash the stack variable in
question.
src/lxc/lxc_driver.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index d6e5e20..37092bc 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1449,7 +1449,6 @@ lxcBuildControllerCmd(lxc_driver_t *driver,
char **veths,
int *ttyFDs,
size_t nttyFDs,
- int logfile,
int handshakefd)
{
size_t i;
@@ -1524,8 +1523,6 @@ lxcBuildControllerCmd(lxc_driver_t *driver,
}
virCommandPreserveFD(cmd, handshakefd);
- virCommandSetOutputFD(cmd, &logfile);
- virCommandSetErrorFD(cmd, &logfile);
return cmd;
cleanup:
@@ -1747,8 +1744,10 @@ static int lxcVmStart(virConnectPtr conn,
vm,
nveths, veths,
ttyFDs, nttyFDs,
- logfd, handshakefds[1])))
+ handshakefds[1])))
goto cleanup;
+ virCommandSetOutputFD(cmd, &logfd);
+ virCommandSetErrorFD(cmd, &logfd);
/* Log timestamp */
if ((timestamp = virTimestamp()) == NULL) {
--
1.7.4.4
13 years