Blame SOURCES/kvm-nbd-client-Lower-min_block-for-block-status-unaligne.patch

7711c0
From 7122c1ace9649d525da8670d5e57aaa8b7c6a686 Mon Sep 17 00:00:00 2001
7711c0
From: John Snow <jsnow@redhat.com>
7711c0
Date: Mon, 6 May 2019 17:56:18 +0200
7711c0
Subject: [PATCH 08/53] nbd/client: Lower min_block for block-status, unaligned
7711c0
 size
7711c0
7711c0
RH-Author: John Snow <jsnow@redhat.com>
7711c0
Message-id: <20190506175629.11079-9-jsnow@redhat.com>
7711c0
Patchwork-id: 87187
7711c0
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/19] nbd/client: Lower min_block for block-status, unaligned size
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 have a latent bug in our NBD client code, tickled by the brand new
7711c0
nbdkit 1.11.10 block status support:
7711c0
7711c0
$ nbdkit --filter=log --filter=truncate -U - \
7711c0
           data data="1" size=511 truncate=64K logfile=/dev/stdout \
7711c0
           --run 'qemu-img convert $nbd /var/tmp/out'
7711c0
...
7711c0
qemu-img: block/io.c:2122: bdrv_co_block_status: Assertion `*pnum && QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset' failed.
7711c0
7711c0
The culprit? Our implementation of .bdrv_co_block_status can return
7711c0
unaligned block status for any server that operates with a lower
7711c0
actual alignment than what we tell the block layer in
7711c0
request_alignment, in violation of the block layer's constraints. To
7711c0
date, we've been unable to trip the bug, because qemu as NBD server
7711c0
always advertises block sizing (at which point it is a server bug if
7711c0
the server sends unaligned status - although qemu 3.1 is such a server
7711c0
and I've sent separate patches for 4.0 both to get the server to obey
7711c0
the spec, and to let the client to tolerate server oddities at EOF).
7711c0
7711c0
But nbdkit does not (yet) advertise block sizing, and therefore is not
7711c0
in violation of the spec for returning block status at whatever
7711c0
boundaries it wants, and those unaligned results can occur anywhere
7711c0
rather than just at EOF. While we are still wise to avoid sending
7711c0
sub-sector read/write requests to a server of unknown origin, we MUST
7711c0
consider that a server telling us block status without an advertised
7711c0
block size is correct.  So, we either have to munge unaligned answers
7711c0
from the server into aligned ones that we hand back to the block
7711c0
layer, or we have to tell the block layer about a smaller alignment.
7711c0
7711c0
Similarly, if the server advertises an image size that is not
7711c0
sector-aligned, we might as well assume that the server intends to let
7711c0
us access those tail bytes, and therefore supports a minimum block
7711c0
size of 1, regardless of whether the server supports block status
7711c0
(although we still need more patches to fix the problem that with an
7711c0
unaligned image, we can send read or block status requests that exceed
7711c0
EOF to the server). Again, qemu as server cannot trip this problem
7711c0
(because it rounds images to sector alignment), but nbdkit advertised
7711c0
unaligned size even before it gained block status support.
7711c0
7711c0
Solve both alignment problems at once by using better heuristics on
7711c0
what alignment to report to the block layer when the server did not
7711c0
give us something to work with. Note that very few NBD servers
7711c0
implement block status (to date, only qemu and nbdkit are known to do
7711c0
so); and as the NBD spec mentioned block sizing constraints prior to
7711c0
documenting block status, it can be assumed that any future
7711c0
implementations of block status are aware that they must advertise
7711c0
block size if they want a minimum size other than 1.
7711c0
7711c0
We've had a long history of struggles with picking the right alignment
7711c0
to use in the block layer, as evidenced by the commit message of
7711c0
fd8d372d (v2.12) that introduced the current choice of forced 512-byte
7711c0
alignment.
7711c0
7711c0
There is no iotest coverage for this fix, because qemu can't provoke
7711c0
it, and I didn't want to make test 241 dependent on nbdkit.
7711c0
7711c0
Fixes: fd8d372d
7711c0
Reported-by: Richard W.M. Jones <rjones@redhat.com>
7711c0
Signed-off-by: Eric Blake <eblake@redhat.com>
7711c0
Message-Id: <20190329042750.14704-3-eblake@redhat.com>
7711c0
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7711c0
Tested-by: Richard W.M. Jones <rjones@redhat.com>
7711c0
(cherry picked from commit 7da537f70d929800ba9c657b8a47a7b827695ccc)
7711c0
Signed-off-by: John Snow <jsnow@redhat.com>
7711c0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
---
7711c0
 block/nbd.c | 19 ++++++++++++++++++-
7711c0
 1 file changed, 18 insertions(+), 1 deletion(-)
7711c0
7711c0
diff --git a/block/nbd.c b/block/nbd.c
7711c0
index 838a8fe..670b9bd 100644
7711c0
--- a/block/nbd.c
7711c0
+++ b/block/nbd.c
7711c0
@@ -437,7 +437,24 @@ static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
7711c0
     uint32_t min = s->info.min_block;
7711c0
     uint32_t max = MIN_NON_ZERO(NBD_MAX_BUFFER_SIZE, s->info.max_block);
7711c0
 
7711c0
-    bs->bl.request_alignment = min ? min : BDRV_SECTOR_SIZE;
7711c0
+    /*
7711c0
+     * If the server did not advertise an alignment:
7711c0
+     * - a size that is not sector-aligned implies that an alignment
7711c0
+     *   of 1 can be used to access those tail bytes
7711c0
+     * - advertisement of block status requires an alignment of 1, so
7711c0
+     *   that we don't violate block layer constraints that block
7711c0
+     *   status is always aligned (as we can't control whether the
7711c0
+     *   server will report sub-sector extents, such as a hole at EOF
7711c0
+     *   on an unaligned POSIX file)
7711c0
+     * - otherwise, assume the server is so old that we are safer avoiding
7711c0
+     *   sub-sector requests
7711c0
+     */
7711c0
+    if (!min) {
7711c0
+        min = (!QEMU_IS_ALIGNED(s->info.size, BDRV_SECTOR_SIZE) ||
7711c0
+               s->info.base_allocation) ? 1 : BDRV_SECTOR_SIZE;
7711c0
+    }
7711c0
+
7711c0
+    bs->bl.request_alignment = min;
7711c0
     bs->bl.max_pdiscard = max;
7711c0
     bs->bl.max_pwrite_zeroes = max;
7711c0
     bs->bl.max_transfer = max;
7711c0
-- 
7711c0
1.8.3.1
7711c0