[RFC libnbd PATCH 0/4] Add CMD_FLAG_DF support
by Eric Blake
RFC because this is an API break, but we haven't declared stable API
yet. If we like it, I'm working on using libnbd to implement the
nbdkit-nbd plugin; knowing whether it is API version 0.1 or 0.2 will
be useful. I also dabbled with allowing optional parameters in python,
although my OCaml is weak enough that there may be cleaner ways to
approach that.
Eric Blake (4):
api: Add flags parameter to pread, trim, cache, disconnect
api: Rearrange flags argument to block_status
python: Let flags parameter be optional
api: Add DF flag support for pread
docs/libnbd.pod | 6 +-
examples/batched-read-write.c | 4 +-
examples/simple-fetch-first-sector.c | 2 +-
examples/simple-reads-and-writes.c | 2 +-
examples/threaded-reads-and-writes.c | 2 +-
generator/generator | 160 ++++++++++++++++++++-------
interop/dirty-bitmap.c | 6 +-
interop/interop.c | 2 +-
lib/disconnect.c | 10 +-
lib/flags.c | 11 ++
lib/rw.c | 51 ++++++---
python/t/460-block-status.py | 8 +-
tests/aio-parallel-load.c | 2 +-
tests/aio-parallel.c | 2 +-
tests/connect-tls.c | 2 +-
tests/errors.c | 2 +-
tests/meta-base-allocation.c | 10 +-
tests/oldstyle.c | 2 +-
tests/synch-parallel.c | 2 +-
19 files changed, 203 insertions(+), 83 deletions(-)
--
2.20.1
5 years, 5 months
[PATCH 0/3] Simple augeas-related changes
by Pino Toscano
- bump the augeas requirement to 1.2.0, and drop an old hack
- add a small helper in the generator
Pino Toscano (3):
build: raise augeas requirement to 1.2.0
appliance: remove custom Shadow augeas lens
daemon: implement OptString for OCaml APIs
appliance/Makefile.am | 6 +--
appliance/guestfs_shadow.aug | 72 ------------------------------------
daemon/augeas.c | 21 +----------
docs/guestfs-building.pod | 2 +-
generator/daemon.ml | 18 ++++++++-
m4/guestfs-libraries.m4 | 4 +-
6 files changed, 23 insertions(+), 100 deletions(-)
delete mode 100644 appliance/guestfs_shadow.aug
--
2.21.0
5 years, 5 months
[libnbd PATCH] connect: Better handling of long socket names
by Eric Blake
Copy various Unix socket handling techniques from nbdkit's nbd plugin:
Silently truncating a socket name rather than issuing an error message
can confuse users. No need to do an explicit memset if the compiler
does it for us via an initializer. No need to use strncpy() which
does wasted effort on short names, when we can use memcpy() given that
we already checked length in order to detect truncation. Linux does
not require a trailing NUL byte in sockaddr_un, so we can allow names
one byte longer.
Not entirely fixed: although the proposed NBD URI document mentions
that URIs can start with a leading (encoded) NUL byte to access the
Linux abstract socket namespace, our use of strlen(sun.sun_path) would
truncate the trailing bytes - but to support abstract sockets in
general, we'd need to add h->unixlen alongside the existing
h->unixsocket.
---
generator/states-connect.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/generator/states-connect.c b/generator/states-connect.c
index a410e34..014f6bb 100644
--- a/generator/states-connect.c
+++ b/generator/states-connect.c
@@ -86,15 +86,20 @@
}
CONNECT_UNIX.START:
- struct sockaddr_un sun;
+ struct sockaddr_un sun = { .sun_family = AF_UNIX };
socklen_t len;
+ size_t socklen;
assert (h->unixsocket != NULL);
- sun.sun_family = AF_UNIX;
- memset (sun.sun_path, 0, sizeof (sun.sun_path));
- strncpy (sun.sun_path, h->unixsocket, sizeof (sun.sun_path) - 1);
- len = sizeof (sun.sun_family) + strlen (sun.sun_path) + 1;
+ socklen = strlen (h->unixsocket);
+ if (socklen > sizeof sun.sun_path) {
+ set_error (ENAMETOOLONG, "socket name too long: %s", h->unixsocket);
+ SET_NEXT_STATE (%.DEAD);
+ return -1;
+ }
+ memcpy (sun.sun_path, h->unixsocket, socklen);
+ len = sizeof sun;
memcpy (&h->connaddr, &sun, len);
h->connaddrlen = len;
--
2.20.1
5 years, 5 months
[PATCH] Use proper label for nbdkit sockets
by Martin Kletzander
While svirt_t can be used for sockets it does not always guarantee that it will
be accessible from a virtual machine. The VM might be running under svirt_tcg_t
context which will need a svirt_tcg_t label on the socket in order to access it.
There is, however, another label, svirt_socket_t, which is accessible from
virt_domain:
# sesearch -A -s svirt_t -c unix_stream_socket -p connectto
...
allow virt_domain svirt_socket_t:unix_stream_socket { ... connectto ... };
...
And virt_domain is a type attribute of both svirt_t and svirt_tcg_t:
# seinfo -x -a virt_domain
Type Attributes: 1
attribute virt_domain;
svirt_t
svirt_tcg_t
Resolves: https://bugzilla.redhat.com/1698437
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
v2v/input_libvirt_vddk.ml | 2 +-
v2v/output_rhv_upload.ml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
index e2efef842e8e..4e36ff71f783 100644
--- a/v2v/input_libvirt_vddk.ml
+++ b/v2v/input_libvirt_vddk.ml
@@ -286,7 +286,7 @@ object
add_arg "--newstyle"; (* use newstyle NBD protocol *)
add_arg "--exportname"; add_arg "/";
if have_selinux then ( (* label the socket so qemu can open it *)
- add_arg "--selinux-label"; add_arg "system_u:object_r:svirt_t:s0"
+ add_arg "--selinux-label"; add_arg "system_u:object_r:svirt_socket_t:s0"
);
(* Name of the plugin. Everything following is a plugin parameter. *)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 0709c8152c4e..5bc6a400725b 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -213,7 +213,7 @@ See also the virt-v2v-output-rhv(1) manual.")
let args =
(* label the socket so qemu can open it *)
if have_selinux then
- args @ ["--selinux-label"; "system_u:object_r:svirt_t:s0"]
+ args @ ["--selinux-label"; "system_u:object_r:svirt_socket_t:s0"]
else args in
args in
--
2.21.0
5 years, 5 months
[PATCH] build: build C sources using OCaml API with CAML_NAME_SPACE
by Pino Toscano
This way no non-namespaced OCaml C symbols are used, reducing the risk
of clashes with other code.
The only exception is ocaml-augeas, which does not build with
CAML_NAME_SPACE; it will be fixed upstream, and it affects only
ocaml-augeas itself.
---
builder/Makefile.am | 2 ++
common/mllibvirt/Makefile.am | 1 +
common/mlpcre/Makefile.am | 1 +
common/mlprogress/Makefile.am | 1 +
common/mltools/Makefile.am | 1 +
common/mlutils/Makefile.am | 1 +
common/mlvisit/Makefile.am | 1 +
common/mlxml/Makefile.am | 1 +
customize/Makefile.am | 1 +
daemon/Makefile.am | 2 ++
ocaml/Makefile.am | 1 +
v2v/Makefile.am | 2 ++
12 files changed, 15 insertions(+)
diff --git a/builder/Makefile.am b/builder/Makefile.am
index b564fadd6..c7caec5cb 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -135,6 +135,7 @@ bin_PROGRAMS += virt-builder virt-builder-repository
virt_builder_SOURCES = $(SOURCES_C)
virt_builder_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I$(builddir) -I$(srcdir) \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
@@ -156,6 +157,7 @@ XOBJECTS = $(BOBJECTS:.cmo=.cmx)
virt_builder_repository_SOURCES = $(REPOSITORY_SOURCES_C)
virt_builder_repository_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I$(builddir) -I$(srcdir) \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/common/mllibvirt/Makefile.am b/common/mllibvirt/Makefile.am
index 12e046c35..181cb9c5c 100644
--- a/common/mllibvirt/Makefile.am
+++ b/common/mllibvirt/Makefile.am
@@ -59,6 +59,7 @@ noinst_DATA = $(MLLIBVIRT_CMA)
libmllibvirt_a_SOURCES = $(SOURCES_C)
libmllibvirt_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where)
diff --git a/common/mlpcre/Makefile.am b/common/mlpcre/Makefile.am
index 6f04256da..1e0b7795c 100644
--- a/common/mlpcre/Makefile.am
+++ b/common/mlpcre/Makefile.am
@@ -49,6 +49,7 @@ noinst_DATA = $(MLPCRE_CMA)
libmlpcre_a_SOURCES = $(SOURCES_C)
libmlpcre_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/common/mlprogress/Makefile.am b/common/mlprogress/Makefile.am
index 9c5ef9baf..d807f6cc8 100644
--- a/common/mlprogress/Makefile.am
+++ b/common/mlprogress/Makefile.am
@@ -50,6 +50,7 @@ noinst_DATA = $(MLPROGRESS_CMA)
libmlprogress_a_SOURCES = $(SOURCES_C)
libmlprogress_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
index ae78b84b7..ba8630033 100644
--- a/common/mltools/Makefile.am
+++ b/common/mltools/Makefile.am
@@ -87,6 +87,7 @@ noinst_DATA = $(MLTOOLS_CMA)
libmltools_a_SOURCES = $(SOURCES_C)
libmltools_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/common/mlutils/Makefile.am b/common/mlutils/Makefile.am
index 45f401268..e86d7bb5f 100644
--- a/common/mlutils/Makefile.am
+++ b/common/mlutils/Makefile.am
@@ -54,6 +54,7 @@ noinst_DATA = $(MLCUTILS_CMA)
# shouldn't be located under lib. XXX
libmlcutils_a_SOURCES = $(SOURCES_C)
libmlcutils_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/common/mlvisit/Makefile.am b/common/mlvisit/Makefile.am
index 53024a1b2..a07c2827d 100644
--- a/common/mlvisit/Makefile.am
+++ b/common/mlvisit/Makefile.am
@@ -51,6 +51,7 @@ noinst_DATA = $(MLVISIT_CMA)
libmlvisit_a_SOURCES = $(SOURCES_C)
libmlvisit_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/common/mlxml/Makefile.am b/common/mlxml/Makefile.am
index 82ab803d1..e56b6fd54 100644
--- a/common/mlxml/Makefile.am
+++ b/common/mlxml/Makefile.am
@@ -50,6 +50,7 @@ noinst_DATA = $(MLXML_CMA)
libmlxml_a_SOURCES = $(SOURCES_C)
libmlxml_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/customize/Makefile.am b/customize/Makefile.am
index 9c0012546..4c246b417 100644
--- a/customize/Makefile.am
+++ b/customize/Makefile.am
@@ -92,6 +92,7 @@ noinst_DATA = $(CUSTOMIZE_CMA)
libcustomize_a_SOURCES = $(SOURCES_C)
libcustomize_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 5d1c222db..49dbf1998 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -239,6 +239,7 @@ guestfsd_LDADD = \
$(OCAML_LIBS)
guestfsd_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I$(shell $(OCAMLC) -where) \
-I$(shell $(OCAMLC) -where)/hivex \
-I$(top_srcdir)/gnulib/lib \
@@ -398,6 +399,7 @@ daemon_utils_tests_SOURCES = \
utils.c \
utils-c.c
daemon_utils_tests_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where) \
diff --git a/ocaml/Makefile.am b/ocaml/Makefile.am
index 4d13eed97..b31e8fc65 100644
--- a/ocaml/Makefile.am
+++ b/ocaml/Makefile.am
@@ -78,6 +78,7 @@ endif
touch $@
libguestfsocaml_a_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-DGUESTFS_PRIVATE=1 \
-I$(top_builddir) -I$(OCAMLLIB) -I$(top_srcdir)/ocaml \
-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index b5761ef46..277b95c31 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -179,6 +179,7 @@ bin_PROGRAMS = virt-v2v virt-v2v-copy-to-local
virt_v2v_SOURCES = $(SOURCES_C)
virt_v2v_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where) \
@@ -254,6 +255,7 @@ virt_v2v_LINK = \
virt_v2v_copy_to_local_SOURCES = \
dummy.c
virt_v2v_copy_to_local_CPPFLAGS = \
+ -DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where) \
--
2.21.0
5 years, 5 months
[RFC nbdkit PATCH 0/2] Add 'nbdkit nbd shared=1' mode
by Eric Blake
I got annoyed by qemu-nbd's default of only allowing a single
connection; combine that with nbdkit's nbd plugin, and even 'qemu-nbd
--list' of nbdkit counts as the single connection and immediately
hangs up. If we introduce a shared mode, then 'qemu-nbd --list' can
connect as many times as it wants without killing the original
qemu-nbd wrapped by nbdkit. But this in turn required a way to wait
for the socket to appear (as nbdkit --exit-with-parent has to be
invoked before exec qemu-nbd, but the socket isn't created until the
latter case).
RFC in part because I wonder if nbdkit should offer a shared mode to
ALL plugins, rather than just the nbd plugin providing its own.
Eric Blake (2):
nbd: Add retry=N parameter
nbd: Add shared=true parameter
plugins/nbd/nbdkit-nbd-plugin.pod | 22 ++++-
plugins/nbd/nbd.c | 134 +++++++++++++++++++++---------
2 files changed, 115 insertions(+), 41 deletions(-)
--
2.20.1
5 years, 6 months
[PATCH libnbd] states: connect_command: Don't set O_NONBLOCK on socket passed to child.
by Richard W.M. Jones
I also made the code a bit more robust about closing the socket along
error paths.
---
generator/states-connect.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/generator/states-connect.c b/generator/states-connect.c
index ba8b240..a69b70f 100644
--- a/generator/states-connect.c
+++ b/generator/states-connect.c
@@ -27,6 +27,7 @@
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
@@ -183,12 +184,12 @@
CONNECT_COMMAND.START:
int sv[2];
pid_t pid;
+ int flags;
assert (!h->sock);
assert (h->argv);
assert (h->argv[0]);
- if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0,
- sv) == -1) {
+ if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) {
SET_NEXT_STATE (%.DEAD);
set_error (errno, "socketpair");
return -1;
@@ -219,13 +220,27 @@
}
/* Parent. */
+ close (sv[1]);
+
h->pid = pid;
+
+ /* The socket must be set to non-blocking only in the parent,
+ * because the child may not be expecting a non-blocking socket.
+ */
+ flags = fcntl (sv[0], F_GETFL, 0);
+ if (flags == -1 ||
+ fcntl (sv[0], F_SETFL, flags|O_NONBLOCK) == -1) {
+ SET_NEXT_STATE (%.DEAD);
+ close (sv[0]);
+ return -1;
+ }
+
h->sock = nbd_internal_socket_create (sv[0]);
if (!h->sock) {
SET_NEXT_STATE (%.DEAD);
+ close (sv[0]);
return -1;
}
- close (sv[1]);
/* The sockets are connected already, we can jump directly to
* receiving the server magic.
--
2.21.0
5 years, 6 months
Interesting libnbd/nbdkit bug
by Richard W.M. Jones
Try doing:
$ nbdsh
nbd> h.connect_command (["nbdkit", "-s", "null"])
At this point you may observe your laptop fan starts to spin and
nbdkit is consuming 100% of CPU. In all other respects everything
works fine, you can send commands etc.
Anyway I tracked the issue down. nbdkit sits in a loop continuously
reading stdin, each read(2) call returning EAGAIN.
The reason for that is because libnbd opens a socketpair with the
SOCK_NONBLOCK option and passes one half directly to the forked
subprocess.
It's obviously a bug, but I'm not sure if libnbd should be unsetting
the SOCK_NONBLOCK option or if nbdkit should be doing it. Maybe both!
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v
5 years, 6 months
[nbdkit PATCH] nbd: Rewrite thread passing to use semaphore rather than pipe
by Eric Blake
I ran some local testing on my Fedora 29 system via:
$ ./nbdkit memory 1m
$ for i in `seq 10`; do
./nbdkit -U - --filter=stats nbd \
statsappend=true statsfile=$file hostname=localhost port=10809 \
--run '~/libnbd/examples/threaded-reads-and-writes $unixsocket'
done
Pre-patch, the runs averaged 1.266s, 1.30E+08 bits/s
Post-patch, the runs averaged 1.154s, 1.42E+08 bits/s
This is roughly 9% performance gain, all because semaphores are
lighter weight than pipes for inter-thread locking. The refactoring
will also make it a bit easier to incorporate the use of libnbd.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Sending this in case someone wants to review my work, but I was happy
enough with the benchmark numbers to go ahead and push this one.
plugins/nbd/nbd.c | 134 +++++++++++++++++++++++-----------------------
1 file changed, 67 insertions(+), 67 deletions(-)
diff --git a/plugins/nbd/nbd.c b/plugins/nbd/nbd.c
index 9039e1b..b2f3446 100644
--- a/plugins/nbd/nbd.c
+++ b/plugins/nbd/nbd.c
@@ -48,6 +48,7 @@
#include <sys/un.h>
#include <assert.h>
#include <pthread.h>
+#include <semaphore.h>
#define NBDKIT_API_VERSION 2
@@ -155,10 +156,8 @@ nbd_config_complete (void)
/* The per-transaction details */
struct transaction {
- union {
- uint64_t cookie;
- int fds[2];
- } u;
+ uint64_t cookie;
+ sem_t sem;
void *buf;
uint64_t offset;
uint32_t count;
@@ -182,6 +181,7 @@ struct handle {
pthread_mutex_t trans_lock; /* Covers access to all fields below */
struct transaction *trans;
+ uint64_t unique;
bool dead;
};
@@ -264,7 +264,7 @@ find_trans_by_cookie (struct handle *h, uint64_t cookie, bool remove)
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&h->trans_lock);
ptr = &h->trans;
while ((trans = *ptr) != NULL) {
- if (cookie == trans->u.cookie)
+ if (cookie == trans->cookie)
break;
ptr = &trans->next;
}
@@ -300,28 +300,27 @@ nbd_request_raw (struct handle *h, uint16_t flags, uint16_t type,
}
/* Perform the request half of a transaction. On success, return the
- non-negative fd for reading the reply; on error return -1. */
-static int
+ transaction; on error return NULL. */
+static struct transaction *
nbd_request_full (struct handle *h, uint16_t flags, uint16_t type,
uint64_t offset, uint32_t count, const void *req_buf,
void *rep_buf, struct nbdkit_extents *extents)
{
int err;
struct transaction *trans;
- int fd;
uint64_t cookie;
trans = calloc (1, sizeof *trans);
if (!trans) {
nbdkit_error ("unable to track transaction: %m");
/* Still in sync with server, so don't mark connection dead */
- return -1;
+ return NULL;
}
- if (pipe (trans->u.fds)) {
- nbdkit_error ("unable to create pipe: %m");
+ if (sem_init (&trans->sem, 0, 0)) {
+ nbdkit_error ("unable to create semaphore: %m");
/* Still in sync with server, so don't mark connection dead */
free (trans);
- return -1;
+ return NULL;
}
trans->buf = rep_buf;
trans->count = rep_buf ? count : 0;
@@ -331,43 +330,39 @@ nbd_request_full (struct handle *h, uint16_t flags, uint16_t type,
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&h->trans_lock);
if (h->dead)
goto err;
+ cookie = trans->cookie = h->unique++;
trans->next = h->trans;
h->trans = trans;
- fd = trans->u.fds[0];
- cookie = trans->u.cookie;
}
if (nbd_request_raw (h, flags, type, offset, count, cookie, req_buf) == 0)
- return fd;
+ return trans;
trans = find_trans_by_cookie (h, cookie, true);
err:
err = errno;
- if (trans) {
- close (trans->u.fds[0]);
- close (trans->u.fds[1]);
- free (trans);
- }
- else
- close (fd);
+ if (sem_destroy (&trans->sem))
+ abort ();
+ free (trans);
+ nbd_mark_dead (h);
errno = err;
- return nbd_mark_dead (h);
+ return NULL;
}
/* Shorthand for nbd_request_full when no extra buffers are involved. */
-static int
+static struct transaction *
nbd_request (struct handle *h, uint16_t flags, uint16_t type, uint64_t offset,
uint32_t count)
{
return nbd_request_full (h, flags, type, offset, count, NULL, NULL, NULL);
}
-/* Read a reply, and look up the fd corresponding to the transaction.
+/* Read a reply, and look up the corresponding transaction.
Return the server's non-negative answer (converted to local errno
value) on success, or -1 on read failure. If structured replies
- were negotiated, fd is set to -1 if there are still more replies
+ were negotiated, trans_out is set to NULL if there are still more replies
expected. */
static int
-nbd_reply_raw (struct handle *h, int *fd)
+nbd_reply_raw (struct handle *h, struct transaction **trans_out)
{
union {
struct simple_reply simple;
@@ -387,7 +382,7 @@ nbd_reply_raw (struct handle *h, int *fd)
bool zero = false; /* if len, whether to read or memset */
uint16_t errlen;
- *fd = -1;
+ *trans_out = NULL;
/* magic and handle overlap between simple and structured replies */
if (read_full (h->fd, &rep, sizeof rep.simple))
return nbd_mark_dead (h);
@@ -573,10 +568,9 @@ nbd_reply_raw (struct handle *h, int *fd)
/* Thanks to structured replies, we must preserve an error in any
earlier chunk for replay during the final chunk. */
if (!more) {
- *fd = trans->u.fds[1];
+ *trans_out = trans;
if (!error)
error = trans->err;
- free (trans);
}
else if (error && !trans->err)
trans->err = error;
@@ -616,19 +610,20 @@ nbd_reader (void *handle)
int r;
while (!done) {
- int fd;
+ struct transaction *trans;
- r = nbd_reply_raw (h, &fd);
+ r = nbd_reply_raw (h, &trans);
if (r >= 0) {
- if (fd < 0)
+ if (!trans)
nbdkit_debug ("partial reply handled, waiting for final reply");
- else if (write (fd, &r, sizeof r) != sizeof r) {
- nbdkit_error ("failed to write pipe: %m");
- abort ();
+ else {
+ trans->err = r;
+ if (sem_post (&trans->sem)) {
+ nbdkit_error ("failed to post semaphore: %m");
+ abort ();
+ }
}
}
- if (fd >= 0)
- close (fd);
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&h->trans_lock);
done = h->dead;
}
@@ -645,27 +640,32 @@ nbd_reader (void *handle)
}
if (!trans)
break;
- if (write (trans->u.fds[1], &r, sizeof r) != sizeof r) {
- nbdkit_error ("failed to write pipe: %m");
+ trans->err = r;
+ if (sem_post (&trans->sem)) {
+ nbdkit_error ("failed to post semaphore: %m");
abort ();
}
- close (trans->u.fds[1]);
- free (trans);
}
return NULL;
}
/* Perform the reply half of a transaction. */
static int
-nbd_reply (struct handle *h, int fd)
+nbd_reply (struct handle *h, struct transaction *trans)
{
int err;
- if (read (fd, &err, sizeof err) != sizeof err) {
- nbdkit_debug ("failed to read pipe: %m");
+ while ((err = sem_wait (&trans->sem)) == -1 && errno == EINTR)
+ /* try again */;
+ if (err) {
+ nbdkit_debug ("failed to wait on semaphore: %m");
err = EIO;
}
- close (fd);
+ else
+ err = trans->err;
+ if (sem_destroy (&trans->sem))
+ abort ();
+ free (trans);
errno = err;
return err ? -1 : 0;
}
@@ -1175,11 +1175,11 @@ nbd_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
uint32_t flags)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
assert (!flags);
- c = nbd_request_full (h, 0, NBD_CMD_READ, offset, count, NULL, buf, NULL);
- return c < 0 ? c : nbd_reply (h, c);
+ s = nbd_request_full (h, 0, NBD_CMD_READ, offset, count, NULL, buf, NULL);
+ return s ? nbd_reply (h, s) : -1;
}
/* Write data to the file. */
@@ -1188,12 +1188,12 @@ nbd_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
uint32_t flags)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
assert (!(flags & ~NBDKIT_FLAG_FUA));
- c = nbd_request_full (h, flags & NBDKIT_FLAG_FUA ? NBD_CMD_FLAG_FUA : 0,
+ s = nbd_request_full (h, flags & NBDKIT_FLAG_FUA ? NBD_CMD_FLAG_FUA : 0,
NBD_CMD_WRITE, offset, count, buf, NULL, NULL);
- return c < 0 ? c : nbd_reply (h, c);
+ return s ? nbd_reply (h, s) : -1;
}
/* Write zeroes to the file. */
@@ -1201,7 +1201,7 @@ static int
nbd_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
int f = 0;
assert (!(flags & ~(NBDKIT_FLAG_FUA | NBDKIT_FLAG_MAY_TRIM)));
@@ -1211,8 +1211,8 @@ nbd_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
f |= NBD_CMD_FLAG_NO_HOLE;
if (flags & NBDKIT_FLAG_FUA)
f |= NBD_CMD_FLAG_FUA;
- c = nbd_request (h, f, NBD_CMD_WRITE_ZEROES, offset, count);
- return c < 0 ? c : nbd_reply (h, c);
+ s = nbd_request (h, f, NBD_CMD_WRITE_ZEROES, offset, count);
+ return s ? nbd_reply (h, s) : -1;
}
/* Trim a portion of the file. */
@@ -1220,12 +1220,12 @@ static int
nbd_trim (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
assert (!(flags & ~NBDKIT_FLAG_FUA));
- c = nbd_request (h, flags & NBDKIT_FLAG_FUA ? NBD_CMD_FLAG_FUA : 0,
+ s = nbd_request (h, flags & NBDKIT_FLAG_FUA ? NBD_CMD_FLAG_FUA : 0,
NBD_CMD_TRIM, offset, count);
- return c < 0 ? c : nbd_reply (h, c);
+ return s ? nbd_reply (h, s) : -1;
}
/* Flush the file to disk. */
@@ -1233,11 +1233,11 @@ static int
nbd_flush (void *handle, uint32_t flags)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
assert (!flags);
- c = nbd_request (h, 0, NBD_CMD_FLUSH, 0, 0);
- return c < 0 ? c : nbd_reply (h, c);
+ s = nbd_request (h, 0, NBD_CMD_FLUSH, 0, 0);
+ return s ? nbd_reply (h, s) : -1;
}
/* Read extents of the file. */
@@ -1246,13 +1246,13 @@ nbd_extents (void *handle, uint32_t count, uint64_t offset,
uint32_t flags, struct nbdkit_extents *extents)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
assert (!(flags & ~NBDKIT_FLAG_REQ_ONE) && h->extents);
- c = nbd_request_full (h, flags & NBDKIT_FLAG_REQ_ONE ? NBD_CMD_FLAG_REQ_ONE : 0,
+ s = nbd_request_full (h, flags & NBDKIT_FLAG_REQ_ONE ? NBD_CMD_FLAG_REQ_ONE : 0,
NBD_CMD_BLOCK_STATUS, offset, count, NULL, NULL,
extents);
- return c < 0 ? c : nbd_reply (h, c);
+ return s ? nbd_reply (h, s) : -1;
}
/* Cache a portion of the file. */
@@ -1260,11 +1260,11 @@ static int
nbd_cache (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
struct handle *h = handle;
- int c;
+ struct transaction *s;
assert (!flags);
- c = nbd_request (h, 0, NBD_CMD_CACHE, offset, count);
- return c < 0 ? c : nbd_reply (h, c);
+ s = nbd_request (h, 0, NBD_CMD_CACHE, offset, count);
+ return s ? nbd_reply (h, s) : -1;
}
static struct nbdkit_plugin plugin = {
--
2.20.1
5 years, 6 months