Mechanical change: Wherever we call any closure with the LIBNBD_CALLBACK_FREE function, we also call nbd_internal_free_callback with the closure's user_data. This allows calls to associate a free callback with any closure via its user_data pointer. --- generator/states-reply-simple.c | 1 + generator/states-reply-structured.c | 24 ++++++++++++++++++------ generator/states-reply.c | 1 + generator/states.c | 1 + lib/aio.c | 4 ++++ lib/debug.c | 4 +++- lib/handle.c | 4 +++- 7 files changed, 31 insertions(+), 8 deletions(-) diff --git a/generator/states-reply-simple.c b/generator/states-reply-simple.c index 9b249ab..9684bc4 100644 --- a/generator/states-reply-simple.c +++ b/generator/states-reply-simple.c @@ -69,6 +69,7 @@ cmd->data, cmd->count, cmd->offset, LIBNBD_READ_DATA, &error) == -1) cmd->error = error ? error : EPROTO; + nbd_internal_free_callback (h, cmd->cb.fn_user_data); cmd->cb.fn.chunk = NULL; /* because we've freed it */ } diff --git a/generator/states-reply-structured.c b/generator/states-reply-structured.c index cdd9f10..b016cd7 100644 --- a/generator/states-reply-structured.c +++ b/generator/states-reply-structured.c @@ -317,8 +317,10 @@ valid_flags (struct nbd_handle *h) 0, offset, LIBNBD_READ_ERROR, &scratch) == -1) if (cmd->error == 0) cmd->error = scratch; - if (valid & LIBNBD_CALLBACK_FREE) + if (valid & LIBNBD_CALLBACK_FREE) { cmd->cb.fn.chunk = NULL; /* because we've freed it */ + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + } } } @@ -408,8 +410,10 @@ valid_flags (struct nbd_handle *h) LIBNBD_READ_DATA, &error) == -1) if (cmd->error == 0) cmd->error = error ? error : EPROTO; - if (valid & LIBNBD_CALLBACK_FREE) + if (valid & LIBNBD_CALLBACK_FREE) { cmd->cb.fn.chunk = NULL; /* because we've freed it */ + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + } } SET_NEXT_STATE (%FINISH); @@ -473,8 +477,10 @@ valid_flags (struct nbd_handle *h) LIBNBD_READ_HOLE, &error) == -1) if (cmd->error == 0) cmd->error = error ? error : EPROTO; - if (valid & LIBNBD_CALLBACK_FREE) + if (valid & LIBNBD_CALLBACK_FREE) { cmd->cb.fn.chunk = NULL; /* because we've freed it */ + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + } } SET_NEXT_STATE(%FINISH); @@ -527,8 +533,10 @@ valid_flags (struct nbd_handle *h) &h->bs_entries[1], (length-4) / 4, &error) == -1) if (cmd->error == 0) cmd->error = error ? error : EPROTO; - if (valid & LIBNBD_CALLBACK_FREE) + if (valid & LIBNBD_CALLBACK_FREE) { cmd->cb.fn.extent = NULL; /* because we've freed it */ + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + } } else /* Emit a debug message, but ignore it. */ @@ -545,12 +553,16 @@ valid_flags (struct nbd_handle *h) flags = be16toh (h->sbuf.sr.structured_reply.flags); if (flags & NBD_REPLY_FLAG_DONE) { - if (cmd->type == NBD_CMD_BLOCK_STATUS && cmd->cb.fn.extent) + if (cmd->type == NBD_CMD_BLOCK_STATUS && cmd->cb.fn.extent) { cmd->cb.fn.extent (LIBNBD_CALLBACK_FREE, cmd->cb.fn_user_data, NULL, 0, NULL, 0, NULL); - if (cmd->type == NBD_CMD_READ && cmd->cb.fn.chunk) + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + } + if (cmd->type == NBD_CMD_READ && cmd->cb.fn.chunk) { cmd->cb.fn.chunk (LIBNBD_CALLBACK_FREE, cmd->cb.fn_user_data, NULL, 0, 0, 0, NULL); + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + } cmd->cb.fn.chunk = NULL; SET_NEXT_STATE (%^FINISH_COMMAND); } diff --git a/generator/states-reply.c b/generator/states-reply.c index 389317e..d5cba1a 100644 --- a/generator/states-reply.c +++ b/generator/states-reply.c @@ -175,6 +175,7 @@ save_reply_state (struct nbd_handle *h) assert (cmd->type != NBD_CMD_DISC); r = cmd->cb.completion (LIBNBD_CALLBACK_VALID|LIBNBD_CALLBACK_FREE, cmd->cb.user_data, &error); + nbd_internal_free_callback (h, cmd->cb.user_data); cmd->cb.completion = NULL; /* because we've freed it */ switch (r) { case -1: diff --git a/generator/states.c b/generator/states.c index a11c1d1..313d2c9 100644 --- a/generator/states.c +++ b/generator/states.c @@ -128,6 +128,7 @@ void abort_commands (struct nbd_handle *h, assert (cmd->type != NBD_CMD_DISC); r = cmd->cb.completion (LIBNBD_CALLBACK_VALID|LIBNBD_CALLBACK_FREE, cmd->cb.user_data, &error); + nbd_internal_free_callback (h, cmd->cb.user_data); cmd->cb.completion = NULL; /* because we've freed it */ switch (r) { case -1: diff --git a/lib/aio.c b/lib/aio.c index 1d26be9..8aa4547 100644 --- a/lib/aio.c +++ b/lib/aio.c @@ -43,6 +43,10 @@ nbd_internal_retire_and_free_command (struct nbd_handle *h, cmd->cb.completion (LIBNBD_CALLBACK_FREE, cmd->cb.user_data, NULL); + /* Free the closures if there's an associated free callback. */ + nbd_internal_free_callback (h, cmd->cb.fn_user_data); + nbd_internal_free_callback (h, cmd->cb.user_data); + /* Free the persistent buffer if there is one and if there's an * associated free callback. */ diff --git a/lib/debug.c b/lib/debug.c index ad4d9cb..34d4184 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -42,9 +42,11 @@ int nbd_unlocked_set_debug_callback (struct nbd_handle *h, nbd_debug_callback debug_callback, void *data) { - if (h->debug_callback) + if (h->debug_callback) { /* ignore return value */ h->debug_callback (LIBNBD_CALLBACK_FREE, h->debug_data, NULL, NULL); + nbd_internal_free_callback (h, h->debug_data); + } h->debug_callback = debug_callback; h->debug_data = data; return 0; diff --git a/lib/handle.c b/lib/handle.c index 0f50e38..5a47bd8 100644 --- a/lib/handle.c +++ b/lib/handle.c @@ -113,8 +113,10 @@ nbd_close (struct nbd_handle *h) return; /* Free user callbacks first. */ - if (h->debug_callback) + if (h->debug_callback) { h->debug_callback (LIBNBD_CALLBACK_FREE, h->debug_data, NULL, NULL); + nbd_internal_free_callback (h, h->debug_data); + } h->debug_callback = NULL; free (h->bs_entries); -- 2.22.0