On 5/21/19 10:15 PM, Eric Blake wrote:
As already noted in our state machine, a client that batches up a
large read followed by large writes, coupled with a server that only
processes commands in order, can result in deadlock (the server won't
read more until we unblock its ability to write out its reply to our
first command; but we aren't willing to read until we are done writing
out our second command). Break the deadlock by teaching the generator
that while we are in the middle of writing a command, we must remain
responsive to read_notify events; if the server has data for us to
read, we should consume that before jumping back into the middle of
our command issue (and consuming a reply can invalidate sbuf, so we
have to drop an assertion in PREPARE_WRITE_PAYLOAD).
That's a hint of a latent bug...
---
generator/generator | 26 ++++++++++++++++++--------
generator/states-issue-command.c | 25 ++++++++++++++++++++++++-
lib/internal.h | 1 +
3 files changed, 43 insertions(+), 9 deletions(-)
@@ -43,12 +52,18 @@
}
return 0;
+ ISSUE_COMMAND.PAUSE_SEND_REQUEST:
+ assert (conn->wlen);
+ assert (conn->cmds_to_issue != NULL);
+ conn->in_write_payload = false;
+ SET_NEXT_STATE (%^REPLY.START);
+ return 0;
...Since processing REPLY is allowed to scribble over conn->sbuf,
+
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));
it is also possible that resuming SEND_REQUEST will be sending scribbled
data. So I need to split conn->sbuf into two parts - a section used for
command issue, and the rest used for REPLY, at which point the assert is
still viable after all.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization:
qemu.org |
libvirt.org