|
|
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 |
|