Although we don't yet have an API that takes an extent64 callback,
it's easier to add the code here separately from the API. We need to
temporarily mark a couple of helper functions in language bindings
with '__attribute__((unused))' to keep the compiler from warning about
them.
The biggest change in this patch is that the array to be passed to the
callback is now populated based on which style API was in use, and
demonstrates that the API is orthogonal from the server's reply size.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
v4: new patch
---
lib/internal.h | 10 +++++--
generator/API.ml | 2 +-
generator/states-reply-chunk.c | 49 +++++++++++++++++++++++-----------
generator/OCaml.ml | 1 +
generator/Python.ml | 1 +
lib/aio.c | 8 ++++--
lib/handle.c | 2 +-
lib/rw.c | 10 ++++---
8 files changed, 58 insertions(+), 25 deletions(-)
diff --git a/lib/internal.h b/lib/internal.h
index 9cad91e3..52a17128 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -80,12 +80,14 @@ struct export {
struct command_cb {
union {
- nbd_extent_callback extent;
+ nbd_extent_callback extent32;
+ nbd_extent64_callback extent64;
nbd_chunk_callback chunk;
nbd_list_callback list;
nbd_context_callback context;
} fn;
nbd_completion_callback completion;
+ bool wide;
};
struct nbd_handle {
@@ -323,7 +325,11 @@ struct nbd_handle {
struct nbd_block_descriptor_32 *narrow;
struct nbd_block_descriptor_64 *wide;
} bs_raw;
- uint32_t *bs_cooked; /* Note that this array has 2*bs_count entries */
+ union {
+ char *storage;
+ uint32_t *narrow; /* Note that this array has 2*bs_count entries... */
+ nbd_extent *wide; /* ...while this is just bs_count entries. */
+ } bs_cooked;
/* Commands which are waiting to be issued [meaning the request
* packet is sent to the server]. This is used as a simple linked
diff --git a/generator/API.ml b/generator/API.ml
index 1fbf147b..858d86df 100644
--- a/generator/API.ml
+++ b/generator/API.ml
@@ -175,7 +175,7 @@ let context_closure =
cbargs = [ CBString "name" ]
}
let all_closures = [ chunk_closure; completion_closure;
- debug_closure; extent_closure; (* extent64_closure; *)
+ debug_closure; extent_closure; extent64_closure;
list_closure;
context_closure ]
diff --git a/generator/states-reply-chunk.c b/generator/states-reply-chunk.c
index 66771fa6..796262d2 100644
--- a/generator/states-reply-chunk.c
+++ b/generator/states-reply-chunk.c
@@ -147,7 +147,8 @@ REPLY.CHUNK_REPLY.START:
!h->meta_valid || h->meta_contexts.len == 0 ||
!bs_reply_length_ok (type, length))
goto resync;
- assert (CALLBACK_IS_NOT_NULL (cmd->cb.fn.extent));
+ ASSERT_MEMBER_ALIAS (struct command_cb, fn.extent32, fn.extent64);
+ assert (CALLBACK_IS_NOT_NULL (cmd->cb.fn.extent32));
if (h->extended_headers != (type == NBD_REPLY_TYPE_BLOCK_STATUS_EXT)) {
debug (h, "wrong block status reply type detected, "
"this is probably a server bug");
@@ -457,7 +458,7 @@ REPLY.CHUNK_REPLY.RECV_BS_HEADER:
assert (cmd->type == NBD_CMD_BLOCK_STATUS);
assert (bs_reply_length_ok (type, h->payload_left));
STATIC_ASSERT (sizeof (struct nbd_block_descriptor_32) ==
- 2 * sizeof *h->bs_cooked,
+ 2 * sizeof *h->bs_cooked.narrow,
_block_desc_is_multiple_of_bs_entry);
ASSERT_MEMBER_ALIAS (union chunk_payload, bs_hdr_32.context_id,
bs_hdr_64.context_id);
@@ -481,16 +482,20 @@ REPLY.CHUNK_REPLY.RECV_BS_HEADER:
}
free (h->bs_raw.storage);
- free (h->bs_cooked);
+ free (h->bs_cooked.storage);
h->bs_raw.storage = malloc (h->payload_left);
- h->bs_cooked = malloc (2 * h->bs_count * sizeof *h->bs_cooked);
- if (h->bs_raw.storage == NULL || h->bs_cooked == NULL) {
+ if (cmd->cb.wide)
+ h->bs_cooked.storage = malloc (h->bs_count * sizeof *h->bs_cooked.wide);
+ else
+ h->bs_cooked.storage = malloc (2 * h->bs_count *
+ sizeof *h->bs_cooked.narrow);
+ if (h->bs_raw.storage == NULL || h->bs_cooked.storage == NULL) {
SET_NEXT_STATE (%.DEAD);
set_error (errno, "malloc");
free (h->bs_raw.storage);
- free (h->bs_cooked);
+ free (h->bs_cooked.storage);
h->bs_raw.storage = NULL;
- h->bs_cooked = NULL;
+ h->bs_cooked.storage = NULL;
return 0;
}
@@ -511,6 +516,7 @@ REPLY.CHUNK_REPLY.RECV_BS_ENTRIES:
uint64_t orig_len, len, flags;
uint64_t total, cap;
bool stop;
+ int ret;
switch (recv_into_rbuf (h)) {
case -1: SET_NEXT_STATE (%.DEAD); return 0;
@@ -523,7 +529,7 @@ REPLY.CHUNK_REPLY.RECV_BS_ENTRIES:
assert (cmd); /* guaranteed by CHECK */
assert (cmd->type == NBD_CMD_BLOCK_STATUS);
- assert (CALLBACK_IS_NOT_NULL (cmd->cb.fn.extent));
+ assert (CALLBACK_IS_NOT_NULL (cmd->cb.fn.extent32));
assert (h->bs_count && h->bs_raw.storage);
assert (h->meta_valid);
@@ -579,7 +585,7 @@ REPLY.CHUNK_REPLY.RECV_BS_ENTRIES:
cmd->error = cmd->error ? : EPROTO;
len = h->exportsize;
}
- if (len > UINT32_MAX) {
+ if (len > UINT32_MAX && !cmd->cb.wide) {
/* Pick an aligned value rather than overflowing 32-bit
* callback; this does not require an error.
*/
@@ -587,7 +593,7 @@ REPLY.CHUNK_REPLY.RECV_BS_ENTRIES:
len = (uint32_t)-MAX_REQUEST_SIZE;
}
flags = be64toh (h->bs_raw.wide[i].status_flags);
- if (flags > UINT32_MAX) {
+ if (flags > UINT32_MAX && !cmd->cb.wide) {
stop = true;
if (i > 0)
break; /* Skip this and later extents; we already made progress */
@@ -610,8 +616,15 @@ REPLY.CHUNK_REPLY.RECV_BS_ENTRIES:
cmd->error = cmd->error ? : EPROTO;
len -= total - cap;
}
- h->bs_cooked[i * 2] = len;
- h->bs_cooked[i * 2 + 1] = flags;
+ if (cmd->cb.wide) {
+ h->bs_cooked.wide[i].length = len;
+ h->bs_cooked.wide[i].flags = flags;
+ }
+ else {
+ assert ((len | flags) <= UINT32_MAX);
+ h->bs_cooked.narrow[i * 2] = len;
+ h->bs_cooked.narrow[i * 2 + 1] = flags;
+ }
}
/* Call the caller's extent function. Yes, our 32-bit public API
@@ -623,10 +636,14 @@ REPLY.CHUNK_REPLY.RECV_BS_ENTRIES:
PRIu64 " and total %" PRIu64 " near extent %zu",
orig_len, total, i);
error = cmd->error;
- if (CALL_CALLBACK (cmd->cb.fn.extent, name, cmd->offset,
- h->bs_cooked, i * 2, &error) == -1)
- if (cmd->error == 0)
- cmd->error = error ? error : EPROTO;
+ if (cmd->cb.wide)
+ ret = CALL_CALLBACK (cmd->cb.fn.extent64, name, cmd->offset,
+ h->bs_cooked.wide, i, &error);
+ else
+ ret = CALL_CALLBACK (cmd->cb.fn.extent32, name, cmd->offset,
+ h->bs_cooked.narrow, i * 2, &error);
+ if (ret == -1 && cmd->error == 0)
+ cmd->error = error ? error : EPROTO;
}
return 0;
diff --git a/generator/OCaml.ml b/generator/OCaml.ml
index 621a4348..ba4c8403 100644
--- a/generator/OCaml.ml
+++ b/generator/OCaml.ml
@@ -592,6 +592,7 @@ let
pr "}\n";
pr "\n";
pr "static int\n";
+ pr "__attribute__ ((unused)) /* XXX temporary hack */\n";
pr "%s_wrapper " cbname;
C.print_cbarg_list ~wrap:true cbargs;
pr "\n";
diff --git a/generator/Python.ml b/generator/Python.ml
index 761f4511..199d0265 100644
--- a/generator/Python.ml
+++ b/generator/Python.ml
@@ -158,6 +158,7 @@ let
let print_python_closure_wrapper { cbname; cbargs } =
pr "/* Wrapper for %s callback. */\n" cbname;
pr "static int\n";
+ pr "__attribute__ ((unused)) /* XXX temporary hack */\n";
pr "%s_wrapper " cbname;
C.print_cbarg_list ~wrap:true cbargs;
pr "\n";
diff --git a/lib/aio.c b/lib/aio.c
index a419ac32..cf9421ec 100644
--- a/lib/aio.c
+++ b/lib/aio.c
@@ -32,8 +32,12 @@ void
nbd_internal_retire_and_free_command (struct command *cmd)
{
/* Free the callbacks. */
- if (cmd->type == NBD_CMD_BLOCK_STATUS)
- FREE_CALLBACK (cmd->cb.fn.extent);
+ if (cmd->type == NBD_CMD_BLOCK_STATUS) {
+ if (cmd->cb.wide)
+ FREE_CALLBACK (cmd->cb.fn.extent64);
+ else
+ FREE_CALLBACK (cmd->cb.fn.extent32);
+ }
if (cmd->type == NBD_CMD_READ)
FREE_CALLBACK (cmd->cb.fn.chunk);
FREE_CALLBACK (cmd->cb.completion);
diff --git a/lib/handle.c b/lib/handle.c
index 1d3aae63..8adb9c73 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -134,7 +134,7 @@ nbd_close (struct nbd_handle *h)
string_vector_empty (&h->querylist);
free (h->bs_raw.storage);
- free (h->bs_cooked);
+ free (h->bs_cooked.storage);
nbd_internal_reset_size_and_flags (h);
for (i = 0; i < h->meta_contexts.len; ++i)
free (h->meta_contexts.ptr[i].name);
diff --git a/lib/rw.c b/lib/rw.c
index 8b2bd4cc..15b309ee 100644
--- a/lib/rw.c
+++ b/lib/rw.c
@@ -290,8 +290,12 @@ nbd_internal_command_common (struct nbd_handle *h,
err:
/* Since we did not queue the command, we must free the callbacks. */
if (cb) {
- if (type == NBD_CMD_BLOCK_STATUS)
- FREE_CALLBACK (cb->fn.extent);
+ if (type == NBD_CMD_BLOCK_STATUS) {
+ if (cb->wide)
+ FREE_CALLBACK (cb->fn.extent32);
+ else
+ FREE_CALLBACK (cb->fn.extent64);
+ }
if (type == NBD_CMD_READ)
FREE_CALLBACK (cb->fn.chunk);
FREE_CALLBACK (cb->completion);
@@ -487,7 +491,7 @@ nbd_unlocked_aio_block_status (struct nbd_handle *h,
nbd_completion_callback *completion,
uint32_t flags)
{
- struct command_cb cb = { .fn.extent = *extent,
+ struct command_cb cb = { .fn.extent32 = *extent, .wide = false,
.completion = *completion };
if (h->strict & LIBNBD_STRICT_COMMANDS) {
--
2.41.0