[Libguestfs] libnbd: When are callbacks freed

Eric Blake eblake at redhat.com
Thu Jul 13 13:01:09 UTC 2023


On Thu, Jul 13, 2023 at 07:13:37AM -0500, Eric Blake wrote:
> > > I have replaced a call to `nbd_opt_info()` with a call to
> > > `nbd_aio_opt_info()` and passed in a completion callback which just
> > > calls `exit(EXIT_FAILURE)`. So if the completion callback is called
> > > the test should fail, which it doesn't, at least not on my machine.
> > 
> > Isn't that OK?  Only .free is required to be called.
> 
> For the context callback (for opt_set_meta), .callback may be called
> zero, one, or multiple times, but .free should be called exactly once.
> But for the completion callback, I agree that the docs state that both
> .callback and .free should each be called exactly once ("On the other
> hand, if a completion callback is supplied (only possible with
> asynchronous commands), it will always be reached exactly once, and
> the completion callback must not ignore the value pointed to by
> C<error>."); we are indeed missing the call to .callback.  I'll work
> on a patch.

Eww, the bug is bigger than just nbd_aio_opt* not always calling
completion.callback exactly once.  With just this diff (to be folded
into the larger patch I'm working on), I'm getting an assertion
failure that we fail to call completion.callback for
nbd_aio_pread_structured when calling nbd_close() prior to the command
running to completion, so I'll have to fix that too.

diff --git i/tests/closure-lifetimes.c w/tests/closure-lifetimes.c
index 9bb4e120..c5ad4c10 100644
--- i/tests/closure-lifetimes.c
+++ w/tests/closure-lifetimes.c
@@ -66,6 +66,7 @@ read_cb (void *opaque,
          uint64_t offset, unsigned status, int *error)
 {
   assert (!read_cb_freed);
+  assert (!completion_cb_called);
   read_cb_called++;
   return 0;
 }
@@ -73,6 +74,7 @@ read_cb (void *opaque,
 static void
 read_cb_free (void *opaque)
 {
+  assert (completion_cb_called);
   read_cb_freed++;
 }

@@ -81,6 +83,7 @@ block_status_cb (void *opaque, const char *meta, uint64_t offset,
                  uint32_t *entries, size_t nr_entries, int *error)
 {
   assert (!block_status_cb_freed);
+  assert (!completion_cb_called);
   block_status_cb_called++;
   return 0;
 }
@@ -88,6 +91,7 @@ block_status_cb (void *opaque, const char *meta, uint64_t offset,
 static void
 block_status_cb_free (void *opaque)
 {
+  assert (completion_cb_called);
   block_status_cb_freed++;
 }

@@ -102,6 +106,7 @@ completion_cb (void *opaque, int *error)
 static void
 completion_cb_free (void *opaque)
 {
+  assert (completion_cb_called);
   completion_cb_freed++;
 }


-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


More information about the Libguestfs mailing list