[Libguestfs] [PATCH libnbd v2 2/4] generator: Callback returns int instead of void.
Richard W.M. Jones
rjones at redhat.com
Tue Jun 4 11:48:55 UTC 2019
On Tue, Jun 04, 2019 at 06:35:13AM -0500, Eric Blake wrote:
> On 6/4/19 4:59 AM, Richard W.M. Jones wrote:
> > Callback functions now return an int instead of a void. This allows
> > in some cases for the callback to indicate that there was an error.
> >
> > This is a small change to the API:
>
> Indeed; and my work to let nbdkit-nbd use libnbd is slightly impacted.
> If I want to support both 0.1.2 and 0.1.x, I now have to do a
> conditional compilation (either based on a configure check or on
> hard-coded version information - we don't yet have a LIBNBD_VERSION
> macro in libnbd.h, but my recent addition LIBNBD_HAVE_NBD_SUPPORTS_URI
> can serve as a hack witness for 0.1.2 vs. later) where I declare a
> typedef to the two different function signatures, then call
> nbd_aio_block_status(..., (type)myfunc) where the cast to (type) is a
> no-op for 0.1.x and casts the return type of int to void for 0.1.2. On
> the other hand, changing my nbdkit-nbd patches to use pkg-config to
> require 0.1.3 or newer is also easy, at which point I don't have to
> worry about back-compat to the older API, and no one else is going to
> try to be compatible across all our various earlier pre-stable API. I'll
> leave it up to you when to actually bump the release version, but it
> looks like I won't be committing my changes to nbdkit-nbd until 0.1.3 is
> actually cut.
TBH I'd just assume latest version, and I'll try to get out 0.1.3 soon
(although not in the next few days).
> >
> > For nbd_set_debug_callback the signature has changed, but the return
> > value is ignored.
> >
> > For nbd_block_status and nbd_aio_block_status the extent function can
> > return an error, which causes the block status command to return an
> > error. Unfortunately this causes us to set the state to dead,
> > although with more effort we could recover from this. Because of this
> > behaviour I didn't document what happens in the error case as we may
> > want to change it in future.
>
> I can give a shot on top of this patch for recovery (my idea: record the
> error, then continue to accept additional reply chunks from the server
> until the final chunk, and merely skip calling the callback when an
> earlier callback error was recorded).
This sounds like the right approach, thanks.
I'll push this with the s/\.$// fix you also mentioned below.
Rich.
> >
> > For Python and OCaml bindings, raising any kind of exception from the
> > callback is equivalent to returning -1 from the C callback.
> > ---
>
> > @@ -3957,24 +3963,34 @@ let print_ocaml_binding (name, { args; ret }) =
> >
> > pr " rv = caml_callbackN_exn (fnv, %d, args);\n"
> > (List.length argnames);
> > - pr " if (Is_exception_result (rv))\n";
> > + pr " if (Is_exception_result (rv)) {\n";
> > + pr " /* XXX This is not really an error as callbacks can return\n";
> > + pr " * an error indication. But perhaps we should direct this\n";
> > + pr " * to a more suitable place or formalize what exception.\n";
>
> Spurious trailing '.'
>
> > + pr " * means error versus unexpected failure.\n";
> > + pr " */\n";
>
> > +++ b/generator/states-reply-structured.c
> > @@ -369,10 +369,16 @@
> > if (context_id == meta_context->context_id)
> > break;
> >
> > - if (meta_context)
> > + if (meta_context) {
> > /* Call the caller's extent function. */
> > - cmd->extent_fn (cmd->data, meta_context->name, cmd->offset,
> > - &h->bs_entries[1], (length-4) / 4);
> > + if (cmd->extent_fn (cmd->data, meta_context->name, cmd->offset,
> > + &h->bs_entries[1], (length-4) / 4) == -1) {
> > + SET_NEXT_STATE (%.DEAD); /* XXX We should be able to recover. */
> > + if (errno == 0) errno = EPROTO;
> > + set_error (errno, "extent function failed");
> > + return -1;
> > + }
> > + }
>
> If nothing else, our testsuite ought to provoke callback failure at
> least once.
>
> > else
> > /* Emit a debug message, but ignore it. */
> > debug (h, "server sent unexpected meta context ID %" PRIu32,
> > diff --git a/interop/dirty-bitmap.c b/interop/dirty-bitmap.c
> > index b3a89d0..8d34173 100644
> > --- a/interop/dirty-bitmap.c
> > +++ b/interop/dirty-bitmap.c
> > @@ -32,7 +32,7 @@ static const char *base_allocation = "base:allocation";
> >
> > static int calls; /* Track which contexts passed through callback */
> >
> > -static void
> > +static int
> > cb (void *data, const char *metacontext, uint64_t offset,
> > uint32_t *entries, size_t len)
> > {
> > @@ -71,6 +71,8 @@ cb (void *data, const char *metacontext, uint64_t offset,
> > fprintf (stderr, "unexpected context %s\n", metacontext);
> > exit (EXIT_FAILURE);
> > }
> > +
> > + return 0;
>
> In fact, having dirty-bitmap be the test to provoke failure, where we
> are expecting more than one context and can thus also prove that failure
> on the first context prevents the callback for the second context from
> being reached, seems like the right place. I'll see what it looks like
> on top of your patch.
>
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc. +1-919-301-3226
> Virtualization: qemu.org | libvirt.org
>
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine. Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/
More information about the Libguestfs
mailing list