|
|
7711c0 |
From c443306c82400c6e04fe4af771552e88abb469a8 Mon Sep 17 00:00:00 2001
|
|
|
7711c0 |
From: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Date: Mon, 6 May 2019 17:56:21 +0200
|
|
|
7711c0 |
Subject: [PATCH 11/53] nbd/client: Support qemu-img convert from unaligned
|
|
|
7711c0 |
size
|
|
|
7711c0 |
|
|
|
7711c0 |
RH-Author: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Message-id: <20190506175629.11079-12-jsnow@redhat.com>
|
|
|
7711c0 |
Patchwork-id: 87184
|
|
|
7711c0 |
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/19] nbd/client: Support qemu-img convert from 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 |
If an NBD server advertises a size that is not a multiple of a sector,
|
|
|
7711c0 |
the block layer rounds up that size, even though we set info.size to
|
|
|
7711c0 |
the exact byte value sent by the server. The block layer then proceeds
|
|
|
7711c0 |
to let us read or query block status on the hole that it added past
|
|
|
7711c0 |
EOF, which the NBD server is unlikely to be happy with. Fortunately,
|
|
|
7711c0 |
qemu as a server never advertizes an unaligned size, so we generally
|
|
|
7711c0 |
don't run into this problem; but the nbdkit server makes it easy to
|
|
|
7711c0 |
test:
|
|
|
7711c0 |
|
|
|
7711c0 |
$ printf %1000d 1 > f1
|
|
|
7711c0 |
$ ~/nbdkit/nbdkit -fv file f1 & pid=$!
|
|
|
7711c0 |
$ qemu-img convert -f raw nbd://localhost:10809 f2
|
|
|
7711c0 |
$ kill $pid
|
|
|
7711c0 |
$ qemu-img compare f1 f2
|
|
|
7711c0 |
|
|
|
7711c0 |
Pre-patch, the server attempts a 1024-byte read, which nbdkit
|
|
|
7711c0 |
rightfully rejects as going beyond its advertised 1000 byte size; the
|
|
|
7711c0 |
conversion fails and the output files differ (not even the first
|
|
|
7711c0 |
sector is copied, because qemu-img does not follow ddrescue's habit of
|
|
|
7711c0 |
trying smaller reads to get as much information as possible in spite
|
|
|
7711c0 |
of errors). Post-patch, the client's attempts to read (and query block
|
|
|
7711c0 |
status, for new enough nbdkit) are properly truncated to the server's
|
|
|
7711c0 |
length, with sane handling of the hole the block layer forced on
|
|
|
7711c0 |
us. Although f2 ends up as a larger file (1024 bytes instead of 1000),
|
|
|
7711c0 |
qemu-img compare shows the two images to have identical contents for
|
|
|
7711c0 |
display to the guest.
|
|
|
7711c0 |
|
|
|
7711c0 |
I didn't add iotests coverage since I didn't want to add a dependency
|
|
|
7711c0 |
on nbdkit in iotests. I also did NOT patch write, trim, or write
|
|
|
7711c0 |
zeroes - these commands continue to fail (usually with ENOSPC, but
|
|
|
7711c0 |
whatever the server chose), because we really can't write to the end
|
|
|
7711c0 |
of the file, and because 'qemu-img convert' is the most common case
|
|
|
7711c0 |
where we care about being tolerant (which is read-only). Perhaps we
|
|
|
7711c0 |
could truncate the request if the client is writing zeros to the tail,
|
|
|
7711c0 |
but that seems like more work, especially if the block layer is fixed
|
|
|
7711c0 |
in 4.1 to track byte-accurate sizing (in which case this patch would
|
|
|
7711c0 |
be reverted as unnecessary).
|
|
|
7711c0 |
|
|
|
7711c0 |
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
Message-Id: <20190329042750.14704-5-eblake@redhat.com>
|
|
|
7711c0 |
Tested-by: Richard W.M. Jones <rjones@redhat.com>
|
|
|
7711c0 |
(cherry picked from commit 9cf638508c0090b33ada4155c7cbb684e08e5ee9)
|
|
|
7711c0 |
Signed-off-by: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
---
|
|
|
7711c0 |
block/nbd-client.c | 39 ++++++++++++++++++++++++++++++++++++++-
|
|
|
7711c0 |
1 file changed, 38 insertions(+), 1 deletion(-)
|
|
|
7711c0 |
|
|
|
7711c0 |
diff --git a/block/nbd-client.c b/block/nbd-client.c
|
|
|
7711c0 |
index 9b5779f..a1a84a8 100644
|
|
|
7711c0 |
--- a/block/nbd-client.c
|
|
|
7711c0 |
+++ b/block/nbd-client.c
|
|
|
7711c0 |
@@ -835,6 +835,25 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
|
|
7711c0 |
if (!bytes) {
|
|
|
7711c0 |
return 0;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
+ /*
|
|
|
7711c0 |
+ * Work around the fact that the block layer doesn't do
|
|
|
7711c0 |
+ * byte-accurate sizing yet - if the read exceeds the server's
|
|
|
7711c0 |
+ * advertised size because the block layer rounded size up, then
|
|
|
7711c0 |
+ * truncate the request to the server and tail-pad with zero.
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+ if (offset >= client->info.size) {
|
|
|
7711c0 |
+ assert(bytes < BDRV_SECTOR_SIZE);
|
|
|
7711c0 |
+ qemu_iovec_memset(qiov, 0, 0, bytes);
|
|
|
7711c0 |
+ return 0;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ if (offset + bytes > client->info.size) {
|
|
|
7711c0 |
+ uint64_t slop = offset + bytes - client->info.size;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ assert(slop < BDRV_SECTOR_SIZE);
|
|
|
7711c0 |
+ qemu_iovec_memset(qiov, bytes - slop, 0, slop);
|
|
|
7711c0 |
+ request.len -= slop;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
ret = nbd_co_send_request(bs, &request, NULL);
|
|
|
7711c0 |
if (ret < 0) {
|
|
|
7711c0 |
return ret;
|
|
|
7711c0 |
@@ -953,7 +972,8 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs,
|
|
|
7711c0 |
.from = offset,
|
|
|
7711c0 |
.len = MIN(MIN_NON_ZERO(QEMU_ALIGN_DOWN(INT_MAX,
|
|
|
7711c0 |
bs->bl.request_alignment),
|
|
|
7711c0 |
- client->info.max_block), bytes),
|
|
|
7711c0 |
+ client->info.max_block),
|
|
|
7711c0 |
+ MIN(bytes, client->info.size - offset)),
|
|
|
7711c0 |
.flags = NBD_CMD_FLAG_REQ_ONE,
|
|
|
7711c0 |
};
|
|
|
7711c0 |
|
|
|
7711c0 |
@@ -964,6 +984,23 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs,
|
|
|
7711c0 |
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
+ /*
|
|
|
7711c0 |
+ * Work around the fact that the block layer doesn't do
|
|
|
7711c0 |
+ * byte-accurate sizing yet - if the status request exceeds the
|
|
|
7711c0 |
+ * server's advertised size because the block layer rounded size
|
|
|
7711c0 |
+ * up, we truncated the request to the server (above), or are
|
|
|
7711c0 |
+ * called on just the hole.
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+ if (offset >= client->info.size) {
|
|
|
7711c0 |
+ *pnum = bytes;
|
|
|
7711c0 |
+ assert(bytes < BDRV_SECTOR_SIZE);
|
|
|
7711c0 |
+ /* Intentionally don't report offset_valid for the hole */
|
|
|
7711c0 |
+ return BDRV_BLOCK_ZERO;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ if (client->info.min_block) {
|
|
|
7711c0 |
+ assert(QEMU_IS_ALIGNED(request.len, client->info.min_block));
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
ret = nbd_co_send_request(bs, &request, NULL);
|
|
|
7711c0 |
if (ret < 0) {
|
|
|
7711c0 |
return ret;
|
|
|
7711c0 |
--
|
|
|
7711c0 |
1.8.3.1
|
|
|
7711c0 |
|