102 lines
3.6 KiB
Diff
102 lines
3.6 KiB
Diff
|
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||
|
Date: Thu, 6 Feb 2020 19:42:45 +0300
|
||
|
Subject: block: fix crash on zero-length unaligned write and read
|
||
|
|
||
|
Git-commit: ac9d00bf7b47acae6b0e42910d9ed55fef3af5b8
|
||
|
|
||
|
Commit 7a3f542fbd "block/io: refactor padding" occasionally dropped
|
||
|
aligning for zero-length request: bdrv_init_padding() blindly return
|
||
|
false if bytes == 0, like there is nothing to align.
|
||
|
|
||
|
This leads the following command to crash:
|
||
|
|
||
|
./qemu-io --image-opts -c 'write 1 0' \
|
||
|
driver=blkdebug,align=512,image.driver=null-co,image.size=512
|
||
|
|
||
|
>> qemu-io: block/io.c:1955: bdrv_aligned_pwritev: Assertion
|
||
|
`(offset & (align - 1)) == 0' failed.
|
||
|
>> Aborted (core dumped)
|
||
|
|
||
|
Prior to 7a3f542fbd we does aligning of such zero requests. Instead of
|
||
|
recovering this behavior let's just do nothing on such requests as it
|
||
|
is useless.
|
||
|
|
||
|
Note that driver may have special meaning of zero-length reqeusts, like
|
||
|
qcow2_co_pwritev_compressed_part, so we can't skip any zero-length
|
||
|
operation. But for unaligned ones, we can't pass it to driver anyway.
|
||
|
|
||
|
This commit also fixes crash in iotest 80 running with -nocache:
|
||
|
|
||
|
./check -nocache -qcow2 80
|
||
|
|
||
|
which crashes on same assertion due to trying to read empty extra data
|
||
|
in qcow2_do_read_snapshots().
|
||
|
|
||
|
Cc: qemu-stable@nongnu.org # v4.2
|
||
|
Fixes: 7a3f542fbd
|
||
|
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
||
|
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||
|
Message-id: 20200206164245.17781-1-vsementsov@virtuozzo.com
|
||
|
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
Signed-off-by: Bruce Rogers <brogers@suse.com>
|
||
|
---
|
||
|
block/io.c | 28 +++++++++++++++++++++++++++-
|
||
|
1 file changed, 27 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/block/io.c b/block/io.c
|
||
|
index f75777f5ea744aac5c9b5872f203..d1f1ee9138c7af82352e9277f22b 100644
|
||
|
--- a/block/io.c
|
||
|
+++ b/block/io.c
|
||
|
@@ -1567,10 +1567,12 @@ static bool bdrv_init_padding(BlockDriverState *bs,
|
||
|
pad->tail = align - pad->tail;
|
||
|
}
|
||
|
|
||
|
- if ((!pad->head && !pad->tail) || !bytes) {
|
||
|
+ if (!pad->head && !pad->tail) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
+ assert(bytes); /* Nothing good in aligning zero-length requests */
|
||
|
+
|
||
|
sum = pad->head + bytes + pad->tail;
|
||
|
pad->buf_len = (sum > align && pad->head && pad->tail) ? 2 * align : align;
|
||
|
pad->buf = qemu_blockalign(bs, pad->buf_len);
|
||
|
@@ -1708,6 +1710,18 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+ if (bytes == 0 && !QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)) {
|
||
|
+ /*
|
||
|
+ * Aligning zero request is nonsense. Even if driver has special meaning
|
||
|
+ * of zero-length (like qcow2_co_pwritev_compressed_part), we can't pass
|
||
|
+ * it to driver due to request_alignment.
|
||
|
+ *
|
||
|
+ * Still, no reason to return an error if someone do unaligned
|
||
|
+ * zero-length read occasionally.
|
||
|
+ */
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
bdrv_inc_in_flight(bs);
|
||
|
|
||
|
/* Don't do copy-on-read if we read data before write operation */
|
||
|
@@ -2115,6 +2129,18 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
|
||
|
return -ENOTSUP;
|
||
|
}
|
||
|
|
||
|
+ if (bytes == 0 && !QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)) {
|
||
|
+ /*
|
||
|
+ * Aligning zero request is nonsense. Even if driver has special meaning
|
||
|
+ * of zero-length (like qcow2_co_pwritev_compressed_part), we can't pass
|
||
|
+ * it to driver due to request_alignment.
|
||
|
+ *
|
||
|
+ * Still, no reason to return an error if someone do unaligned
|
||
|
+ * zero-length write occasionally.
|
||
|
+ */
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
bdrv_inc_in_flight(bs);
|
||
|
/*
|
||
|
* Align write if necessary by performing a read-modify-write cycle.
|