qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org, libguestfs@redhat.com, vsementsov@yandex-team.ru
Subject: [PATCH v4 13/24] nbd/server: Refactor handling of request payload
Date: Thu,  8 Jun 2023 08:56:42 -0500	[thread overview]
Message-ID: <20230608135653.2918540-14-eblake@redhat.com> (raw)
In-Reply-To: <20230608135653.2918540-1-eblake@redhat.com>

Upcoming additions to support NBD 64-bit effect lengths allow for the
possibility to distinguish between payload length (capped at 32M) and
effect length (up to 63 bits).  Without that extension, only the
NBD_CMD_WRITE request has a payload; but with the extension, it makes
sense to allow at least NBD_CMD_BLOCK_STATUS to have both a payload
and effect length (where the payload is a limited-size struct that in
turns gives the real effect length as well as a subset of known ids
for which status is requested).  Other future NBD commands may also
have a request payload, so the 64-bit extension introduces a new
NBD_CMD_FLAG_PAYLOAD_LEN that distinguishes between whether the header
length is a payload length or an effect length, rather than
hard-coding the decision based on the command.  Note that we do not
support the payload version of BLOCK_STATUS yet.

For this patch, no semantic change is intended for a compliant client.
For a non-compliant client, it is possible that the error behavior
changes (a different message, a change on whether the connection is
killed or remains alive for the next command, or so forth), in part
because req->complete is set later on some paths, but all errors
should still be handled gracefully.

Signed-off-by: Eric Blake <eblake@redhat.com>
---

v4: less indentation on several 'if's [Vladimir]
---
 nbd/server.c     | 76 ++++++++++++++++++++++++++++++------------------
 nbd/trace-events |  1 +
 2 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/nbd/server.c b/nbd/server.c
index 4ac05d0cd7b..d7dc29f0445 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -2329,6 +2329,8 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, NBDRequest *
                                                Error **errp)
 {
     NBDClient *client = req->client;
+    bool extended_with_payload;
+    unsigned payload_len = 0;
     int valid_flags;
     int ret;

@@ -2342,48 +2344,63 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, NBDRequest *
     trace_nbd_co_receive_request_decode_type(request->cookie, request->type,
                                              nbd_cmd_lookup(request->type));

-    if (request->type != NBD_CMD_WRITE) {
-        /* No payload, we are ready to read the next request.  */
-        req->complete = true;
-    }
-
     if (request->type == NBD_CMD_DISC) {
         /* Special case: we're going to disconnect without a reply,
          * whether or not flags, from, or len are bogus */
+        req->complete = true;
         return -EIO;
     }

-    if (request->type == NBD_CMD_READ || request->type == NBD_CMD_WRITE ||
-        request->type == NBD_CMD_CACHE)
-    {
-        if (request->len > NBD_MAX_BUFFER_SIZE) {
-            error_setg(errp, "len (%" PRIu64" ) is larger than max len (%u)",
-                       request->len, NBD_MAX_BUFFER_SIZE);
-            return -EINVAL;
+    /* Payload and buffer handling. */
+    extended_with_payload = client->mode >= NBD_MODE_EXTENDED &&
+        (request->flags & NBD_CMD_FLAG_PAYLOAD_LEN);
+    if ((request->type == NBD_CMD_READ || request->type == NBD_CMD_WRITE ||
+         request->type == NBD_CMD_CACHE || extended_with_payload) &&
+        request->len > NBD_MAX_BUFFER_SIZE) {
+        error_setg(errp, "len (%" PRIu64" ) is larger than max len (%u)",
+                   request->len, NBD_MAX_BUFFER_SIZE);
+        return -EINVAL;
+    }
+
+    if (request->type == NBD_CMD_WRITE || extended_with_payload) {
+        payload_len = request->len;
+        if (request->type != NBD_CMD_WRITE) {
+            /*
+             * For now, we don't support payloads on other
+             * commands; but we can keep the connection alive.
+             */
+            request->len = 0;
+        } else if (client->mode >= NBD_MODE_EXTENDED &&
+                   !extended_with_payload) {
+            /* The client is noncompliant. Trace it, but proceed. */
+            trace_nbd_co_receive_ext_payload_compliance(request->from,
+                                                        request->len);
         }
+    }

-        if (request->type != NBD_CMD_CACHE) {
-            req->data = blk_try_blockalign(client->exp->common.blk,
-                                           request->len);
-            if (req->data == NULL) {
-                error_setg(errp, "No memory");
-                return -ENOMEM;
-            }
+    if (request->type == NBD_CMD_WRITE || request->type == NBD_CMD_READ) {
+        req->data = blk_try_blockalign(client->exp->common.blk,
+                                       request->len);
+        if (req->data == NULL) {
+            error_setg(errp, "No memory");
+            return -ENOMEM;
         }
     }

-    if (request->type == NBD_CMD_WRITE) {
-        assert(request->len <= NBD_MAX_BUFFER_SIZE);
-        if (nbd_read(client->ioc, req->data, request->len, "CMD_WRITE data",
-                     errp) < 0)
-        {
+    if (payload_len) {
+        if (req->data) {
+            ret = nbd_read(client->ioc, req->data, payload_len,
+                           "CMD_WRITE data", errp);
+        } else {
+            ret = nbd_drop(client->ioc, payload_len, errp);
+        }
+        if (ret < 0) {
             return -EIO;
         }
-        req->complete = true;
-
         trace_nbd_co_receive_request_payload_received(request->cookie,
-                                                      request->len);
+                                                      payload_len);
     }
+    req->complete = true;

     /* Sanity checks. */
     if (client->exp->nbdflags & NBD_FLAG_READ_ONLY &&
@@ -2413,7 +2430,10 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, NBDRequest *
                                               client->check_align);
     }
     valid_flags = NBD_CMD_FLAG_FUA;
-    if (request->type == NBD_CMD_READ && client->mode >= NBD_MODE_STRUCTURED) {
+    if (request->type == NBD_CMD_WRITE && client->mode >= NBD_MODE_EXTENDED) {
+        valid_flags |= NBD_CMD_FLAG_PAYLOAD_LEN;
+    } else if (request->type == NBD_CMD_READ &&
+               client->mode >= NBD_MODE_STRUCTURED) {
         valid_flags |= NBD_CMD_FLAG_DF;
     } else if (request->type == NBD_CMD_WRITE_ZEROES) {
         valid_flags |= NBD_CMD_FLAG_NO_HOLE | NBD_CMD_FLAG_FAST_ZERO;
diff --git a/nbd/trace-events b/nbd/trace-events
index 3338da2be2a..6a34d7f027a 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -71,6 +71,7 @@ nbd_co_send_extents(uint64_t cookie, unsigned int extents, uint32_t id, uint64_t
 nbd_co_send_chunk_error(uint64_t cookie, int err, const char *errname, const char *msg) "Send structured error reply: cookie = %" PRIu64 ", error = %d (%s), msg = '%s'"
 nbd_co_receive_request_decode_type(uint64_t cookie, uint16_t type, const char *name) "Decoding type: cookie = %" PRIu64 ", type = %" PRIu16 " (%s)"
 nbd_co_receive_request_payload_received(uint64_t cookie, uint64_t len) "Payload received: cookie = %" PRIu64 ", len = %" PRIu64
+nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client sent non-compliant write without payload flag: from=0x%" PRIx64 ", len=0x%" PRIx64
 nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx64 ", align=0x%" PRIx32
 nbd_trip(void) "Reading request"

-- 
2.40.1



  parent reply	other threads:[~2023-06-08 13:58 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-08 13:56 [PATCH v4 00/24] qemu patches for 64-bit NBD extensions Eric Blake
2023-06-08 13:56 ` [PATCH v4 01/24] nbd/client: Use smarter assert Eric Blake
2023-06-08 13:56 ` [PATCH v4 02/24] nbd: Consistent typedef usage in header Eric Blake
2023-06-08 14:17   ` [Libguestfs] " Eric Blake
2023-06-12 11:59     ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 03/24] nbd/server: Prepare for alternate-size headers Eric Blake
2023-06-12 13:53   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 04/24] nbd/server: Refactor to pass full request around Eric Blake
2023-06-08 13:56 ` [PATCH v4 05/24] nbd: s/handle/cookie/ to match NBD spec Eric Blake
2023-06-08 14:32   ` [Libguestfs] " Eric Blake
2023-06-12 14:12   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 06/24] nbd/client: Simplify cookie vs. index computation Eric Blake
2023-06-12 14:27   ` Vladimir Sementsov-Ogievskiy
2023-06-12 19:13     ` Eric Blake
2023-06-08 13:56 ` [PATCH v4 07/24] nbd/client: Add safety check on chunk payload length Eric Blake
2023-06-08 13:56 ` [PATCH v4 08/24] nbd: Use enum for various negotiation modes Eric Blake
2023-06-12 14:39   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 09/24] nbd: Replace bool structured_reply with mode enum Eric Blake
2023-06-12 15:07   ` Vladimir Sementsov-Ogievskiy
2023-06-12 19:24     ` [Libguestfs] " Eric Blake
2023-07-19 20:11       ` Eric Blake
2023-06-08 13:56 ` [PATCH v4 10/24] nbd/client: Pass mode through to nbd_send_request Eric Blake
2023-06-12 15:48   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 11/24] nbd: Add types for extended headers Eric Blake
2023-06-12 16:11   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 12/24] nbd: Prepare for 64-bit request effect lengths Eric Blake
2023-06-08 18:26   ` [Libguestfs] " Eric Blake
2023-06-16 18:16   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` Eric Blake [this message]
2023-06-08 18:29   ` [Libguestfs] [PATCH v4 13/24] nbd/server: Refactor handling of request payload Eric Blake
2023-06-16 18:29     ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 14/24] nbd/server: Prepare to receive extended header requests Eric Blake
2023-06-16 18:35   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 15/24] nbd/server: Prepare to send extended header replies Eric Blake
2023-06-16 18:48   ` Vladimir Sementsov-Ogievskiy
2023-08-04 19:28     ` Eric Blake
2023-08-07 17:20       ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 16/24] nbd/server: Support 64-bit block status Eric Blake
2023-06-27 13:23   ` Vladimir Sementsov-Ogievskiy
2023-08-04 19:36     ` Eric Blake
2023-08-07 17:28       ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 17/24] nbd/server: Enable initial support for extended headers Eric Blake
2023-06-27 13:26   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 18/24] nbd/client: Plumb errp through nbd_receive_replies Eric Blake
2023-06-08 19:10   ` [Libguestfs] " Eric Blake
2023-06-27 13:31   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 19/24] nbd/client: Initial support for extended headers Eric Blake
2023-06-27 14:22   ` Vladimir Sementsov-Ogievskiy
2023-08-07 19:20     ` Eric Blake
2023-06-08 13:56 ` [PATCH v4 20/24] nbd/client: Accept 64-bit block status chunks Eric Blake
2023-06-27 14:50   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 21/24] nbd/client: Request extended headers during negotiation Eric Blake
2023-06-27 14:55   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 22/24] nbd/server: Refactor list of negotiated meta contexts Eric Blake
2023-06-27 15:11   ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 23/24] nbd/server: Prepare for per-request filtering of BLOCK_STATUS Eric Blake
2023-06-08 19:15   ` [Libguestfs] " Eric Blake
2023-06-27 15:19     ` Vladimir Sementsov-Ogievskiy
2023-06-08 13:56 ` [PATCH v4 24/24] nbd/server: Add FLAG_PAYLOAD support to CMD_BLOCK_STATUS Eric Blake
2023-06-08 19:19   ` [Libguestfs] " Eric Blake
2023-06-27 19:42   ` Vladimir Sementsov-Ogievskiy
2023-08-07 20:23     ` [Libguestfs] " Eric Blake

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230608135653.2918540-14-eblake@redhat.com \
    --to=eblake@redhat.com \
    --cc=libguestfs@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=vsementsov@yandex-team.ru \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).