Eric Blake
2019-Jul-25 21:55 UTC
[Libguestfs] [libnbd PATCH] lib: Reduce number of read/block_status callbacks
When the server sets NBD_REPLY_FLAG_DONE on a data or block status chunk, we can use that fact to pass (VALID|FREE) and avoid a separate callback later just for FREE. --- As I've been promising in other threads... generator/states-reply-structured.c | 33 +++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/generator/states-reply-structured.c b/generator/states-reply-structured.c index 2ef8d20..20b0e9e 100644 --- a/generator/states-reply-structured.c +++ b/generator/states-reply-structured.c @@ -18,6 +18,19 @@ /* State machine for parsing structured replies from the server. */ +static unsigned +valid_flags (struct nbd_handle *h) +{ + unsigned valid = LIBNBD_CALLBACK_VALID; + uint16_t flags = be16toh (h->sbuf.sr.structured_reply.flags); + + if (flags & NBD_REPLY_FLAG_DONE) + valid |= LIBNBD_CALLBACK_FREE; + return valid; +} + +/*----- End of prologue. -----*/ + /* STATE MACHINE */ { REPLY.STRUCTURED_REPLY.START: /* We've only read the simple_reply. The structured_reply is longer, @@ -293,16 +306,19 @@ } if (cmd->type == NBD_CMD_READ && cmd->cb.fn.read) { int scratch = error; + unsigned valid = valid_flags (h); /* Different from successful reads: inform the callback about the * current error rather than any earlier one. If the callback fails * without setting errno, then use the server's error below. */ - if (cmd->cb.fn.read (LIBNBD_CALLBACK_VALID, cmd->cb.fn_user_data, + if (cmd->cb.fn.read (valid, cmd->cb.fn_user_data, cmd->data + (offset - cmd->offset), 0, offset, LIBNBD_READ_ERROR, &scratch) == -1) if (cmd->error == 0) cmd->error = scratch; + if (valid & LIBNBD_CALLBACK_FREE) + cmd->cb.fn.read = NULL; /* because we've freed it */ } } @@ -384,13 +400,16 @@ assert (cmd); /* guaranteed by CHECK */ if (cmd->cb.fn.read) { int error = cmd->error; + unsigned valid = valid_flags (h); - if (cmd->cb.fn.read (LIBNBD_CALLBACK_VALID, cmd->cb.fn_user_data, + if (cmd->cb.fn.read (valid, cmd->cb.fn_user_data, cmd->data + (offset - cmd->offset), length - sizeof offset, offset, LIBNBD_READ_DATA, &error) == -1) if (cmd->error == 0) cmd->error = error ? error : EPROTO; + if (valid & LIBNBD_CALLBACK_FREE) + cmd->cb.fn.read = NULL; /* because we've freed it */ } SET_NEXT_STATE (%FINISH); @@ -446,13 +465,16 @@ memset (cmd->data + offset, 0, length); if (cmd->cb.fn.read) { int error = cmd->error; + unsigned valid = valid_flags (h); - if (cmd->cb.fn.read (LIBNBD_CALLBACK_VALID, cmd->cb.fn_user_data, + if (cmd->cb.fn.read (valid, cmd->cb.fn_user_data, cmd->data + offset, length, cmd->offset + offset, LIBNBD_READ_HOLE, &error) == -1) if (cmd->error == 0) cmd->error = error ? error : EPROTO; + if (valid & LIBNBD_CALLBACK_FREE) + cmd->cb.fn.read = NULL; /* because we've freed it */ } SET_NEXT_STATE(%FINISH); @@ -498,12 +520,15 @@ if (meta_context) { /* Call the caller's extent function. */ int error = cmd->error; + unsigned valid = valid_flags (h); - if (cmd->cb.fn.extent (LIBNBD_CALLBACK_VALID, cmd->cb.fn_user_data, + if (cmd->cb.fn.extent (valid, cmd->cb.fn_user_data, meta_context->name, cmd->offset, &h->bs_entries[1], (length-4) / 4, &error) == -1) if (cmd->error == 0) cmd->error = error ? error : EPROTO; + if (valid & LIBNBD_CALLBACK_FREE) + cmd->cb.fn.extent = NULL; /* because we've freed it */ } else /* Emit a debug message, but ignore it. */ -- 2.20.1
Possibly Parallel Threads
- [PATCH libnbd 7/7] api: Remove the valid_flag from all callbacks.
- [PATCH libnbd 4/7] lib: Allow closure user_data to be associated with a free callback.
- [PATCH libnbd] generator: Generate typedefs automatically for Closure arguments.
- [PATCH libnbd 2/4] api: Add free function and remove valid_flag parameter.
- Re: [PATCH libnbd 2/3] lib: Implement closure lifetimes.