Blame SOURCES/kvm-nbd-server-Trace-client-noncompliance-on-unaligned-r.patch

7711c0
From a3c2d291823493cd39a79e0b2a38c9af29090cf0 Mon Sep 17 00:00:00 2001
7711c0
From: John Snow <jsnow@redhat.com>
7711c0
Date: Mon, 6 May 2019 17:56:26 +0200
7711c0
Subject: [PATCH 16/53] nbd/server: Trace client noncompliance on unaligned
7711c0
 requests
7711c0
7711c0
RH-Author: John Snow <jsnow@redhat.com>
7711c0
Message-id: <20190506175629.11079-17-jsnow@redhat.com>
7711c0
Patchwork-id: 87198
7711c0
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 16/19] nbd/server: Trace client noncompliance on unaligned requests
7711c0
Bugzilla: 1692018
7711c0
RH-Acked-by: Max Reitz <mreitz@redhat.com>
7711c0
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
7711c0
RH-Acked-by: Thomas Huth <thuth@redhat.com>
7711c0
7711c0
From: Eric Blake <eblake@redhat.com>
7711c0
7711c0
We've recently added traces for clients to flag server non-compliance;
7711c0
let's do the same for servers to flag client non-compliance. According
7711c0
to the spec, if the client requests NBD_INFO_BLOCK_SIZE, it is
7711c0
promising to send all requests aligned to those boundaries.  Of
7711c0
course, if the client does not request NBD_INFO_BLOCK_SIZE, then it
7711c0
made no promises so we shouldn't flag anything; and because we are
7711c0
willing to handle clients that made no promises (the spec allows us to
7711c0
use NBD_REP_ERR_BLOCK_SIZE_REQD if we had been unwilling), we already
7711c0
have to handle unaligned requests (which the block layer already does
7711c0
on our behalf).  So even though the spec allows us to return EINVAL
7711c0
for clients that promised to behave, it's easier to always answer
7711c0
unaligned requests.  Still, flagging non-compliance can be useful in
7711c0
debugging a client that is trying to be maximally portable.
7711c0
7711c0
Qemu as client used to have one spot where it sent non-compliant
7711c0
requests: if the server sends an unaligned reply to
7711c0
NBD_CMD_BLOCK_STATUS, and the client was iterating over the entire
7711c0
disk, the next request would start at that unaligned point; this was
7711c0
fixed in commit a39286dd when the client was taught to work around
7711c0
server non-compliance; but is equally fixed if the server is patched
7711c0
to not send unaligned replies in the first place (yes, qemu 4.0 as
7711c0
server still has few such bugs, although they will be patched in
7711c0
4.1). Fortunately, I did not find any more spots where qemu as client
7711c0
was non-compliant. I was able to test the patch by using the following
7711c0
hack to convince qemu-io to run various unaligned commands, coupled
7711c0
with serving 512-byte alignment by intentionally omitting '-f raw' on
7711c0
the server while viewing server traces.
7711c0
7711c0
| diff --git i/nbd/client.c w/nbd/client.c
7711c0
| index 427980bdd22..1858b2aac35 100644
7711c0
| --- i/nbd/client.c
7711c0
| +++ w/nbd/client.c
7711c0
| @@ -449,6 +449,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt,
7711c0
|                  nbd_send_opt_abort(ioc);
7711c0
|                  return -1;
7711c0
|              }
7711c0
| +            info->min_block = 1;//hack
7711c0
|              if (!is_power_of_2(info->min_block)) {
7711c0
|                  error_setg(errp, "server minimum block size %" PRIu32
7711c0
|                             " is not a power of two", info->min_block);
7711c0
7711c0
Signed-off-by: Eric Blake <eblake@redhat.com>
7711c0
Message-Id: <20190403030526.12258-3-eblake@redhat.com>
7711c0
[eblake: address minor review nits]
7711c0
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7711c0
(cherry picked from commit 6e280648d21d8c0aa8a101b62d0732cd1e608743)
7711c0
Signed-off-by: John Snow <jsnow@redhat.com>
7711c0
7711c0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
---
7711c0
 nbd/server.c     | 17 ++++++++++++++++-
7711c0
 nbd/trace-events |  1 +
7711c0
 2 files changed, 17 insertions(+), 1 deletion(-)
7711c0
7711c0
diff --git a/nbd/server.c b/nbd/server.c
7711c0
index 6ae2154..42f77ae 100644
7711c0
--- a/nbd/server.c
7711c0
+++ b/nbd/server.c
7711c0
@@ -124,6 +124,8 @@ struct NBDClient {
7711c0
     int nb_requests;
7711c0
     bool closing;
7711c0
 
7711c0
+    uint32_t check_align; /* If non-zero, check for aligned client requests */
7711c0
+
7711c0
     bool structured_reply;
7711c0
     NBDExportMetaContexts export_meta;
7711c0
 
7711c0
@@ -533,6 +535,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
7711c0
     bool blocksize = false;
7711c0
     uint32_t sizes[3];
7711c0
     char buf[sizeof(uint64_t) + sizeof(uint16_t)];
7711c0
+    uint32_t check_align = 0;
7711c0
 
7711c0
     /* Client sends:
7711c0
         4 bytes: L, name length (can be 0)
7711c0
@@ -609,7 +612,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
7711c0
      * whether this is OPT_INFO or OPT_GO. */
7711c0
     /* minimum - 1 for back-compat, or actual if client will obey it. */
7711c0
     if (client->opt == NBD_OPT_INFO || blocksize) {
7711c0
-        sizes[0] = blk_get_request_alignment(exp->blk);
7711c0
+        check_align = sizes[0] = blk_get_request_alignment(exp->blk);
7711c0
     } else {
7711c0
         sizes[0] = 1;
7711c0
     }
7711c0
@@ -660,6 +663,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
7711c0
 
7711c0
     if (client->opt == NBD_OPT_GO) {
7711c0
         client->exp = exp;
7711c0
+        client->check_align = check_align;
7711c0
         QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
7711c0
         nbd_export_get(client->exp);
7711c0
         nbd_check_meta_export(client);
7711c0
@@ -2126,6 +2130,17 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
7711c0
         return (request->type == NBD_CMD_WRITE ||
7711c0
                 request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL;
7711c0
     }
7711c0
+    if (client->check_align && !QEMU_IS_ALIGNED(request->from | request->len,
7711c0
+                                                client->check_align)) {
7711c0
+        /*
7711c0
+         * The block layer gracefully handles unaligned requests, but
7711c0
+         * it's still worth tracing client non-compliance
7711c0
+         */
7711c0
+        trace_nbd_co_receive_align_compliance(nbd_cmd_lookup(request->type),
7711c0
+                                              request->from,
7711c0
+                                              request->len,
7711c0
+                                              client->check_align);
7711c0
+    }
7711c0
     valid_flags = NBD_CMD_FLAG_FUA;
7711c0
     if (request->type == NBD_CMD_READ && client->structured_reply) {
7711c0
         valid_flags |= NBD_CMD_FLAG_DF;
7711c0
diff --git a/nbd/trace-events b/nbd/trace-events
7711c0
index 7f10ebd..bd42cc8 100644
7711c0
--- a/nbd/trace-events
7711c0
+++ b/nbd/trace-events
7711c0
@@ -71,4 +71,5 @@ nbd_co_send_structured_error(uint64_t handle, int err, const char *errname, cons
7711c0
 nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)"
7711c0
 nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32
7711c0
 nbd_co_receive_request_cmd_write(uint32_t len) "Reading %" PRIu32 " byte(s)"
7711c0
+nbd_co_receive_align_compliance(const char *op, uint64_t from, uint32_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx32 ", align=0x%" PRIx32
7711c0
 nbd_trip(void) "Reading request"
7711c0
-- 
7711c0
1.8.3.1
7711c0