Right now, NBD includes potentially platform-specific error values in the protocol.
Luckily, most common error values are more or less universal: of all errno values <= 34 (up to ERANGE), only 11 seems to differ across the common platforms: it is EAGAIN on Windows and Linux, but it is EDEADLK on Darwin and the *BSDs. This patch defines a limited set of errno values that are valid for the NBD protocol, and specifies recommendations for what error to return in specific corner cases. The set of errno values is roughly based on the errors listed in the read(2) and write(2) man pages, with some exception: - ENOMEM is added for servers that implement copy-on-write or other formats that require dynamic allocation. - EDQUOT is not part of the universal set of errors; it can be changed to ENOSPC on the wire format. - EFBIG is part of the universal set of errors, but it is also changed to ENOSPC because it is pretty similar to ENOSPC or EDQUOT. The server is changed to match the recommendations. Signed-off-by: Paolo Bonzini <[email protected]> --- doc/proto.txt | 26 +++++++++++++++++++++++++- nbd-server.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/doc/proto.txt b/doc/proto.txt index 1eb37de..0ca46f2 100644 --- a/doc/proto.txt +++ b/doc/proto.txt @@ -43,7 +43,7 @@ now, the only flag is NBD_CMD_FLAG_FUA (bit 16), "Force unit access". The reply contains three fields: a 32 bit magic number ('magic'), a 32 bit error code ('error'; 0, unless an error occurred in which case it is -the errno of the error on the server side), and the same 64 bit handle +one of the error values documented below), and the same 64 bit handle that the corresponding request had in its 'handle' field. In case the reply is sent in response to a read request and the error field is 0 (zero), the reply header is immediately followed by request.len bytes of @@ -65,6 +65,30 @@ if present, else by fdatasync() of that file (note not all files in a multifile environment). NBD_CMD_FLAG_FUA will not be set unless NBD_FLAG_SEND_FUA is set. +Error values +------------ + +The following error values are defined: + + Integer value Short name Description + ------------------------------------------------------------- + 1 EPERM Operation not permitted + 5 EIO Input/output error + 12 ENOMEM Cannot allocate memory + 22 EINVAL Invalid argument + 28 ENOSPC No space left on device + +The server should return ENOSPC if it receives a write request including +one or more sectors beyond the size of the device. It should return +EINVAL if it receives a read or trim request including one or more +sectors beyond the size of the device. It also should map the EDQUOT +and EFBIG errors to ENOSPC. Finally, it should return EPERM if it +receives a write or trim request on a read-only export. Which error to +return in any other case is not specified by the NBD protocol. + +Negotiation +=========== + There are two versions of the negotiation: the 'old' style (nbd <= 2.9.16) and the 'new' style (nbd >= 2.9.17, though due to a bug it does not work with anything below 2.9.18). What follows is a description of diff --git a/nbd-server.c b/nbd-server.c index 3075a0e..d5745f9 100644 --- a/nbd-server.c +++ b/nbd-server.c @@ -1554,12 +1554,33 @@ void send_export_info(CLIENT* client) { } } +static int nbd_errno(int errcode) { + switch (errcode) { + case EPERM: + return htonl(1); + case EIO: + return htonl(5); + case ENOMEM: + return htonl(12); + case EINVAL: + return htonl(22); + case EFBIG: + case ENOSPC: +#ifdef EDQUOT + case EDQUOT: +#endif + return htonl(28); // ENOSPC + default: + return htonl(22); // EINVAL + } +} + /** sending macro. */ #define SEND(net,reply) { writeit( net, &reply, sizeof( reply )); \ if (client->transactionlogfd != -1) \ writeit(client->transactionlogfd, &reply, sizeof(reply)); } /** error macro. */ -#define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; } +#define ERROR(client,reply,errcode) { reply.error = nbd_errno(errcode); SEND(client->net,reply); reply.error = 0; } /** * Serve a file to a single client. * @@ -1609,7 +1630,8 @@ int mainloop(CLIENT *client) { memcpy(reply.handle, request.handle, sizeof(reply.handle)); - if ((command==NBD_CMD_WRITE) || (command==NBD_CMD_READ)) { + if ((command==NBD_CMD_WRITE) || (command==NBD_CMD_READ) || + (command==NBD_CMD_TRIM)) { if (request.from + len < request.from) { // 64 bit overflow!! DEBUG("[Number too large!]"); ERROR(client, reply, EINVAL); @@ -1618,7 +1640,7 @@ int mainloop(CLIENT *client) { if (((off_t)request.from + len) > client->exportsize) { DEBUG("[RANGE!]"); - ERROR(client, reply, EINVAL); + ERROR(client, reply, (command==NBD_CMD_WRITE) ? ENOSPC : EINVAL); continue; } @@ -1711,6 +1733,12 @@ int mainloop(CLIENT *client) { case NBD_CMD_TRIM: /* The kernel module sets discard_zeroes_data == 0, * so it is okay to do nothing. */ + if ((client->server->flags & F_READONLY) || + (client->server->flags & F_AUTOREADONLY)) { + DEBUG("[TRIM to READONLY!]"); + ERROR(client, reply, EPERM); + continue; + } if (exptrim(&request, client)) { DEBUG("Trim failed: %m"); ERROR(client, reply, errno); -- 2.3.5 ------------------------------------------------------------------------------ One dashboard for servers and applications across Physical-Virtual-Cloud Widest out-of-the-box monitoring support with 50+ applications Performance metrics, stats and reports that give you Actionable Insights Deep dive visibility with transaction tracing using APM Insight. http://ad.doubleclick.net/ddm/clk/290420510;117567292;y _______________________________________________ Nbd-general mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/nbd-general
