On 11/11/2017 08:33 PM, Eric Blake wrote: > This is a minimal implementation of an NBD forwarder; it lets us > convert between old and newstyle connections (great if a client > expects one style but the real server only provides the other), > or add TLS safety on top of a server without having to rewrite > that server. Right now, the real server is expected to live > on a named Unix socket, and the transactions are serialized > rather than interleaved; further enhancements could be made to > also permit TCP servers or more efficient transmission. > > I also envision the possibility of enhancing our testsuite to > use NBD forwarding as a great test of our server. > > Signed-off-by: Eric Blake <ebl...@redhat.com> >
> +/* Read an entire buffer, returning 0 on success or -1 with errno set */ > +static int read_full (int fd, void *buf, size_t len) > +{ > + ssize_t r; > + > + while (len) { > + r = read (fd, buf, len); > + if (r < 0) { > + if (errno == EINTR || errno == EAGAIN) > + continue; > + return -1; > + } > + if (!r) { > + /* Unexpected EOF */ > + errno = EBADMSG; This errno value does not travel over for the wire in NBD during transmission phase, and results in the client seeing EINVAL; however, based on how this function is sometimes called... [1] > +/* Write an entire buffer, returning 0 on success or -1 with errno set */ > +static int write_full (int fd, const void *buf, size_t len) > +{ > + ssize_t r; > + > + while (len) { > + r = write (fd, buf, len); > + if (r < 0) { > + if (errno == EINTR || errno == EAGAIN) > + continue; > + return -1; Likewise when this function fails with EPIPE... [2] > +static int nbd_request (struct handle *h, uint32_t type, uint64_t offset, > + uint32_t count, uint64_t *cookie) > +{ > + struct request req = { > + .magic = htobe32 (NBD_REQUEST_MAGIC), > + /* TODO nbdkit should have a way to pass flags, separate from cmd type */ > + .type = htobe32 (type), > + .handle = htobe64 (h->cookie), > + .offset = htobe64 (offset), > + .count = htobe32 (count), > + }; > + int r; > + > + /* TODO full parallel support requires tracking cookies for handling > + out-of-order responses */ > + *cookie = h->cookie++; > + if (h->dead) { > + nbdkit_set_error (ESHUTDOWN); > + return -1; > + } > + nbdkit_debug ("sending request with type %d and cookie %" PRIu64, type, > + *cookie); > + r = write_full (h->fd, &req, sizeof req); > + if (r < 0) > + h->dead = true; [2] ...failing with ESHUTDOWN instead of EPIPE (which turns into EINVAL) > + return r; > +} > + > +static int nbd_reply (struct handle *h, uint64_t cookie) > +{ > + struct reply rep; > + > + if (read_full (h->fd, &rep, sizeof rep) < 0) { > + h->dead = true; > + return -1; [1] ...and failing with ESHUTDOWN instead of EBADMSG (which turns into EINVAL) make more sense from the client's point of view. I'm going to submit a v2 of this patch; I also have an idea up my sleeve for how to make things interleave (by having a dedicated reader pthread, as well as a pipe() pair per transaction to manage the handoffs between transactions issuing the request and the reader thread handling the reply) that I hope to include in my v2 series if I can get it further in my testing. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs