On Mon, Nov 01, 2010 at 02:38:14PM -0600, Eric Blake wrote:
On 11/01/2010 10:12 AM, Daniel P. Berrange wrote:
> To avoid the need for duplicating implementations of virStream
> drivers, provide a generic implementation that can handle any
> FD based stream. This code is copied from the existing impl
> in the QEMU driver, with the locking moved into the stream
> impl, and addition of a read callback
>
> The FD stream code will refuse to operate on regular files or
> block devices, since those can't report EAGAIN properly when
> they would block on I/O
>
> * include/libvirt/virterror.h, include/libvirt/virterror.h: Add
> VIR_FROM_STREAM error domain
> * src/qemu/qemu_driver.c: Remove code obsoleted by the new
> generic streams driver.
> * src/fdstream.h, src/fdstream.c, src/fdstream.c,
> src/libvirt_private.syms: Generic reusable FD based streams
> ---
> include/libvirt/virterror.h | 3 +-
> src/Makefile.am | 1 +
> src/fdstream.c | 472 +++++++++++++++++++++++++++++++++++++++++++
> src/fdstream.h | 44 ++++
> src/libvirt_private.syms | 7 +
> src/qemu/qemu_driver.c | 284 +-------------------------
> src/util/virterror.c | 3 +
> 7 files changed, 534 insertions(+), 280 deletions(-)
> create mode 100644 src/fdstream.c
> create mode 100644 src/fdstream.h
>
> diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
> index 94d686c..abf6945 100644
> --- a/include/libvirt/virterror.h
> +++ b/include/libvirt/virterror.h
> @@ -73,7 +73,8 @@ typedef enum {
> VIR_FROM_NWFILTER, /* Error from network filter driver */
> VIR_FROM_HOOK, /* Error from Synchronous hooks */
> VIR_FROM_DOMAIN_SNAPSHOT, /* Error from domain snapshot */
> - VIR_FROM_AUDIT /* Error from auditing subsystem */
> + VIR_FROM_AUDIT, /* Error from auditing subsystem */
> + VIR_FROM_STREAMS, /* Error from I/O streams */
> } virErrorDomain;
Is the switch from C89 style (no trailing comma) to the C99 style
(optional trailing comma permitted) intentional? Personally, I like it,
since adding a new value at the end no longer requires a random-looking
diff of the previous entry just to add a comma.
IMHO, leaving off the comma needlessly enlarges future patches
because 2 lines have to be changed to add an entry instead
of just one.
> +++ b/src/fdstream.c
> +#include <config.h>
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <sys/socket.h>
These are okay,
> +#include <sys/un.h>
but this is missing on Mingw, with no gnulib replacement as of yet. Do
we need to add some HAVE_SYS_UN_H checks?
Yes, i guess so.
> +#include <netinet/in.h>
> +#include <netinet/tcp.h>
Likewise for HAVE_NETINET_TCP_H.
Doesn't gnulib take care of TCP socket portability for us ?
> +static int
> +virFDStreamClose(virStreamPtr st)
> +{
> + struct virFDStreamData *fdst = st->privateData;
> +
> + if (!fdst)
> + return 0;
> +
> + virMutexLock(&fdst->lock);
> +
> + virFDStreamFree(fdst);
Before freeing the stream, should this use VIR_CLOSE(fdst->fd) and
return any close failures to the caller?
virFDStreamFree is what actually closes the FD in this case,
and could return an error status to the caller.
> +static int virFDStreamWrite(virStreamPtr st, const char *bytes, size_t nbytes)
Should this return ssize_t...
No, this has to return an int, to match the public API calling
convention.
> +{
> + struct virFDStreamData *fdst = st->privateData;
> + int ret;
and s/int/ssize_t/...
> +
> + if (!fdst) {
> + streamsReportError(VIR_ERR_INTERNAL_ERROR,
> + "%s", _("stream is not open"));
> + return -1;
> + }
> +
> + virMutexLock(&fdst->lock);
> +
> +retry:
> + ret = write(fdst->fd, bytes, nbytes);
...to avoid (theoretical) truncation from ssize_t to int?
It doesn't help, because the API has to return 'int' regardless.
> +
> +
> +int virFDStreamConnectUNIX(virStreamPtr st,
> + const char *path,
> + bool abstract)
Should this code be conditionally compiled for Linux, and omitted on mingw?
Yep, probably should.
> +int virFDStreamOpenFile(virStreamPtr st,
> + const char *path,
> + int flags)
> +{
> + int fd = open(path, flags);
This should check that (flags & O_CREAT) == 0, so as to avoid the kernel
interpreting a third argument of garbage mode flags if a broken caller
passes O_CREAT.
> + /* Thanks to the POSIX i/o model, we can't reliably get
> + * non-blocking I/O on block devs/regular files. To
> + * support those we need to fork a helper process todo
> + * the I/O so we just have a fifo. Or use AIO :-(
> + */
> + if ((st->flags & VIR_STREAM_NONBLOCK) &&
> + (!S_ISCHR(sb.st_mode) &&
> + !S_ISFIFO(sb.st_mode))) {
Should we also permit S_ISSOCK as an fd that supports reliable
non-blocking behavior?
AFAIK, there's no way to open a socket as a path on the
filesystem is there ? So there'd be no way that open(path)
could return an FD for which S_ISSOCK() is true.
> +int virFDStreamCreateFile(virStreamPtr st,
> + const char *path,
> + int flags,
> + mode_t mode)
> +{
> + int fd = open(path, flags, mode);
Except for the difference in open() calls, this looks identical to
virFDStreamOpenFile; can they share implementations?
When I fix the code to deal with non-blocking I/O on regular
files, they will probably need some different handling in
each case.
> +++ b/src/util/virterror.c
> @@ -190,6 +190,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
> case VIR_FROM_AUDIT:
> dom = "Audit";
> break;
> + case VIR_FROM_STREAMS:
> + dom = "Streams ";
In just this context, I wondered why the trailing space? Then looking
at the entire file, I instead wonder: why are VIR_FROM_NWFILTER and
VIR_FROM_AUDIT the only ones that lack trailing space?
Looks like a bug to me.
Regards,
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://deltacloud.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|