1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/* nbd client library in userspace: state machine
* Copyright Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* State machine for parsing simple replies from the server. */
STATE_MACHINE {
REPLY.SIMPLE_REPLY.START:
struct command *cmd = h->reply_cmd;
uint32_t error;
error = be32toh (h->sbuf.reply.hdr.simple.error);
if (cmd == NULL) {
/* Unexpected reply. If error was set or we have structured
* replies, we know there should be no payload, so the next byte
* on the wire (if any) will be another reply, and we can let
* FINISH_COMMAND diagnose/ignore the server bug. If not, we lack
* context to know whether the server thinks it was responding to
* NBD_CMD_READ, so it is safer to move to DEAD now than to risk
* consuming a server's potential data payload as a reply stream
* (even though we would be likely to produce a magic number
* mismatch on the next pass that would also move us to DEAD).
*/
if (error || h->structured_replies)
SET_NEXT_STATE (%^FINISH_COMMAND);
else {
uint64_t cookie = be64toh (h->sbuf.reply.hdr.simple.cookie);
SET_NEXT_STATE (%.DEAD);
set_error (EPROTO,
"no matching cookie %" PRIu64 " found for server reply, "
"this is probably a server bug", cookie);
}
return 0;
}
/* Although a server with structured replies negotiated is in error
* for using a simple reply to NBD_CMD_READ, we can cope with the
* packet, but diagnose it by failing the read with EPROTO.
*/
if (cmd->type == NBD_CMD_READ && h->structured_replies) {
debug (h, "server sent unexpected simple reply for read");
if (cmd->error == 0)
cmd->error = EPROTO;
}
error = nbd_internal_errno_of_nbd_error (error);
if (cmd->error == 0)
cmd->error = error;
if (error == 0 && cmd->type == NBD_CMD_READ) {
h->rbuf = cmd->data;
h->rlen = cmd->count;
cmd->data_seen += cmd->count;
SET_NEXT_STATE (%RECV_READ_PAYLOAD);
}
else {
SET_NEXT_STATE (%^FINISH_COMMAND);
}
return 0;
REPLY.SIMPLE_REPLY.RECV_READ_PAYLOAD:
struct command *cmd = h->reply_cmd;
switch (recv_into_rbuf (h)) {
case -1: SET_NEXT_STATE (%.DEAD); return 0;
case 1:
save_reply_state (h);
SET_NEXT_STATE (%.READY);
return 0;
case 0:
/* guaranteed by START */
assert (cmd);
if (CALLBACK_IS_NOT_NULL (cmd->cb.fn.chunk)) {
int error = cmd->error;
if (CALL_CALLBACK (cmd->cb.fn.chunk,
cmd->data, cmd->count,
cmd->offset, LIBNBD_READ_DATA,
&error) == -1)
cmd->error = error ? error : EPROTO;
}
SET_NEXT_STATE (%^FINISH_COMMAND);
}
return 0;
} /* END STATE MACHINE */
|