In order to handle reading an in-flight response while in the middle of sending a second command, we'll need a way to jump back into the middle of a command being sent. This is easier if the state that sets wbuf/wlen is distinct from the state that reads into wbuf and alters wlen, and also easier if we don't move the command to the in-flight queue until after the writes finish (since the previous patch was careful to queue new pending commands to the end of the list, the head of the list is always the current command needing to be sent). --- generator/generator | 14 ++++++++++ generator/states-issue-command.c | 45 ++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/generator/generator b/generator/generator index a1523e1..f8d59a0 100755 --- a/generator/generator +++ b/generator/generator @@ -638,12 +638,26 @@ and issue_command_state_machine = [ external_events = [ NotifyWrite, "" ]; }; + State { + default_state with + name = "PREPARE_WRITE_PAYLOAD"; + comment = "Prepare the write payload to send to the remote server"; + external_events = []; + }; + State { default_state with name = "SEND_WRITE_PAYLOAD"; comment = "Sending the write payload to the remote server"; external_events = [ NotifyWrite, "" ]; }; + +State { + default_state with + name = "FINISH"; + comment = "Finish issuing a command"; + external_events = []; + }; ] (* Receiving a reply from the server. *) diff --git a/generator/states-issue-command.c b/generator/states-issue-command.c index a57f40f..e24ea34 100644 --- a/generator/states-issue-command.c +++ b/generator/states-issue-command.c @@ -24,9 +24,6 @@ assert (conn->cmds_to_issue != NULL); cmd = conn->cmds_to_issue; - conn->cmds_to_issue = cmd->next; - cmd->next = conn->cmds_in_flight; - conn->cmds_in_flight = cmd; conn->sbuf.request.magic = htobe32 (NBD_REQUEST_MAGIC); conn->sbuf.request.flags = htobe16 (cmd->flags); @@ -40,29 +37,43 @@ return 0; ISSUE_COMMAND.SEND_REQUEST: - struct command_in_flight *cmd; - switch (send_from_wbuf (conn)) { case -1: SET_NEXT_STATE (%.DEAD); return -1; - case 0: - assert (conn->cmds_in_flight != NULL); - cmd = conn->cmds_in_flight; - assert (cmd->handle == be64toh (conn->sbuf.request.handle)); - if (cmd->type == NBD_CMD_WRITE) { - conn->wbuf = cmd->data; - conn->wlen = cmd->count; - SET_NEXT_STATE (%SEND_WRITE_PAYLOAD); - } - else - SET_NEXT_STATE (%.READY); + case 0: SET_NEXT_STATE (%PREPARE_WRITE_PAYLOAD); } return 0; + ISSUE_COMMAND.PREPARE_WRITE_PAYLOAD: + struct command_in_flight *cmd; + + assert (conn->cmds_to_issue != NULL); + cmd = conn->cmds_to_issue; + assert (cmd->handle == be64toh (conn->sbuf.request.handle)); + if (cmd->type == NBD_CMD_WRITE) { + conn->wbuf = cmd->data; + conn->wlen = cmd->count; + SET_NEXT_STATE (%SEND_WRITE_PAYLOAD); + } + else + SET_NEXT_STATE (%FINISH); + return 0; + ISSUE_COMMAND.SEND_WRITE_PAYLOAD: switch (send_from_wbuf (conn)) { case -1: SET_NEXT_STATE (%.DEAD); return -1; - case 0: SET_NEXT_STATE (%.READY); + case 0: SET_NEXT_STATE (%FINISH); } return 0; + ISSUE_COMMAND.FINISH: + struct command_in_flight *cmd; + + assert (conn->cmds_to_issue != NULL); + cmd = conn->cmds_to_issue; + conn->cmds_to_issue = cmd->next; + cmd->next = conn->cmds_in_flight; + conn->cmds_in_flight = cmd; + SET_NEXT_STATE (%.READY); + return 0; + } /* END STATE MACHINE */ -- 2.20.1