A generic client exploiting multiple in-flight commands should be
prepared for out-of-order responses (and should probably ensure that
there are no 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 of being fully
serialized may depend on commands being processed in strict FIFO
order, and we should not get in the way of that. When adding commands
to be issued, and when moving a server's reply into commands to inform
the client about, we need to insert at the end rather than the head of
the appropriate list. Only the cmds_in_flight list does not have to
care about maintaining FIFO ordering.
---
generator/states-reply.c | 13 ++++++++++---
lib/rw.c | 13 ++++++++++---
2 files changed, 20 insertions(+), 6 deletions(-)
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/rw.c b/lib/rw.c
index 9dfce97..fa7dc52 100644
--- a/lib/rw.c
+++ b/lib/rw.c
@@ -246,7 +246,7 @@ command_common (struct nbd_connection *conn,
uint16_t flags, uint16_t type,
uint64_t offset, uint64_t count, void *data)
{
- struct command_in_flight *cmd;
+ struct command_in_flight *cmd, *prev_cmd;
switch (type) {
/* Commands which send or receive data are limited to MAX_REQUEST_SIZE. */
@@ -296,8 +296,15 @@ command_common (struct nbd_connection *conn,
if (conn->structured_replies && cmd->data && type ==
NBD_CMD_READ)
memset (cmd->data, 0, cmd->count);
- cmd->next = conn->cmds_to_issue;
- conn->cmds_to_issue = cmd;
+ /* Stick the command at the end of the list */
+ if (conn->cmds_to_issue != NULL) {
+ prev_cmd = conn->cmds_to_issue;
+ while (prev_cmd->next)
+ prev_cmd = prev_cmd->next;
+ prev_cmd->next = cmd;
+ }
+ else
+ conn->cmds_to_issue = cmd;
return cmd;
}
--
2.20.1