[Libguestfs] [libnbd PATCH v3 3/7] commands: Expose FIFO ordering of server completions

Eric Blake eblake at redhat.com
Wed May 22 21:29:03 UTC 2019


A generic client exploiting multiple in-flight commands should be
prepared for out-of-order responses (and should probably ensure that
there are no offset/count overlaps between parallel in-flight commands
to avoid unspecified disk contents if the server acts on commands in
an arbitrary order or even exposing non-atomic splicing effects).  But
a specific client aware of a specific server's behavior may have
reason to depend on fully serialized answers. For example, knowing
whether a write response arrived prior to a flush response can be used
to learn whether the flush covered the write, or whether another flush
may be needed.  We need both a way to let the client query which
command completed first (a new nbd_aio_peek_command_completed) and to
treat the completed list as a queue rather than a stack to preserve
FIFO order.
---
 generator/generator      | 12 ++++++++++++
 generator/states-reply.c | 13 ++++++++++---
 lib/aio.c                | 13 +++++++++++++
 3 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/generator/generator b/generator/generator
index 60dfb72..a1523e1 100755
--- a/generator/generator
+++ b/generator/generator
@@ -1628,6 +1628,18 @@ The C<handle> parameter is the unique 64 bit handle for the command,
 as returned by a call such as C<nbd_aio_pread>.";
   };

+  "aio_peek_command_completed", {
+    default_call with
+    args = []; ret = RInt64;
+    shortdesc = "check if any command has completed";
+    longdesc = "\
+Return the unique 64 bit handle of the first non-retired but completed
+command, or -1 if no command is awaiting retirement. Any handle
+returned by this function must still be passed to
+C<aio_command_completed> to actually retire the command and learn
+whether the command was successful.";
+  };
+
   "connection_state", {
     default_call with
     args = []; ret = RConstString;
diff --git a/generator/states-reply.c b/generator/states-reply.c
index 93f6cda..45362d4 100644
--- a/generator/states-reply.c
+++ b/generator/states-reply.c
@@ -103,13 +103,20 @@
   }
   assert (cmd != NULL);

-  /* Move it to the cmds_done list. */
+  /* Move it to the end of the cmds_done list. */
   if (prev_cmd != NULL)
     prev_cmd->next = cmd->next;
   else
     conn->cmds_in_flight = cmd->next;
-  cmd->next = conn->cmds_done;
-  conn->cmds_done = cmd;
+  cmd->next = NULL;
+  if (conn->cmds_done) {
+    prev_cmd = conn->cmds_done;
+    while (prev_cmd->next)
+      prev_cmd = prev_cmd->next;
+    prev_cmd->next = cmd;
+  }
+  else
+    conn->cmds_done = cmd;

   SET_NEXT_STATE (%.READY);
   return 0;
diff --git a/lib/aio.c b/lib/aio.c
index c7764f8..105651f 100644
--- a/lib/aio.c
+++ b/lib/aio.c
@@ -158,3 +158,16 @@ nbd_unlocked_aio_command_completed (struct nbd_connection *conn,
              nbd_internal_name_of_nbd_cmd (type), strerror (error));
   return -1;
 }
+
+int64_t
+nbd_unlocked_aio_peek_command_completed (struct nbd_connection *conn)
+{
+  if (conn->cmds_done != NULL)
+    return conn->cmds_done->handle;
+
+  if (conn->cmds_in_flight != NULL || conn->cmds_to_issue != NULL)
+    set_error (0, "no in-flight command has completed yet");
+  else
+    set_error (0, "no commands are in flight");
+  return -1;
+}
-- 
2.20.1




More information about the Libguestfs mailing list