Block patches for 5.0-rc2:
- Fix double QLIST_REMOVE() and potential request object leak in xen-block - Prevent a potential assertion failure in qcow2's code for compressed clusters by rejecting invalid (unaligned) requests with -EIO - Prevent discards on qcow2 v2 images from making backing data reappear - Make qemu-img convert report I/O error locations by byte offsets consistently - Fix for potential I/O test errors (accidental globbing due to missing quotes) -----BEGIN PGP SIGNATURE----- iQFGBAABCAAwFiEEkb62CjDbPohX0Rgp9AfbAGHVz0AFAl6MckkSHG1yZWl0ekBy ZWRoYXQuY29tAAoJEPQH2wBh1c9AGLcH/A8ML6mjaJtwjZG4hL2IuJiA5q+EwswL BSM9JBmShFHGkienYhjwMHBgU/QzXMjmsPNLSvdrn09Zd/0C3VjoHVZqfp67o3Cc /LmQxnMGfSD8OL/hQmuWeW4S0DKV4rFXFYfbeLFiVpdaS6Sy4BOXiM/ozVJz/IjA G+rdr9qk6ICWu940VfQXfl1nNxKw9fUebMH0p2SXbrKDmP4m+Op+Phr9rs506+wj Of+RwFQ5mkiou8k5s3ODTzD71gZmWsWP2xOGZ3n5ydVMuwZnblCmaTj2V/tbtBYN zQILgnwNYagYWrdOIjJepmC+oHa2tN3tJnMLMYRrB29BJN3AOcB7Etc= =0rFv -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2020-04-07' into staging Block patches for 5.0-rc2: - Fix double QLIST_REMOVE() and potential request object leak in xen-block - Prevent a potential assertion failure in qcow2's code for compressed clusters by rejecting invalid (unaligned) requests with -EIO - Prevent discards on qcow2 v2 images from making backing data reappear - Make qemu-img convert report I/O error locations by byte offsets consistently - Fix for potential I/O test errors (accidental globbing due to missing quotes) # gpg: Signature made Tue 07 Apr 2020 13:30:01 BST # gpg: using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40 # gpg: issuer "mreitz@redhat.com" # gpg: Good signature from "Max Reitz <mreitz@redhat.com>" [full] # Primary key fingerprint: 91BE B60A 30DB 3E88 57D1 1829 F407 DB00 61D5 CF40 * remotes/maxreitz/tags/pull-block-2020-04-07: xen-block: Fix double qlist remove and request leak iotests/common.pattern: Quote echos qcow2: Check request size in qcow2_co_pwritev_compressed_part() qemu-img: Report convert errors by bytes, not sectors qcow2: Forbid discard in qcow2 v2 images with backing files Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
339205e7ef
@ -3784,6 +3784,12 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
|||||||
int ret;
|
int ret;
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
|
|
||||||
|
/* If the image does not support QCOW_OFLAG_ZERO then discarding
|
||||||
|
* clusters could expose stale data from the backing file. */
|
||||||
|
if (s->qcow_version < 3 && bs->backing) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
if (!QEMU_IS_ALIGNED(offset | bytes, s->cluster_size)) {
|
if (!QEMU_IS_ALIGNED(offset | bytes, s->cluster_size)) {
|
||||||
assert(bytes < s->cluster_size);
|
assert(bytes < s->cluster_size);
|
||||||
/* Ignore partial clusters, except for the special case of the
|
/* Ignore partial clusters, except for the special case of the
|
||||||
@ -4349,6 +4355,11 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (offset_into_cluster(s, bytes) &&
|
||||||
|
(offset + bytes) != (bs->total_sectors << BDRV_SECTOR_BITS)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
while (bytes && aio_task_pool_status(aio) == 0) {
|
while (bytes && aio_task_pool_status(aio) == 0) {
|
||||||
uint64_t chunk_size = MIN(bytes, s->cluster_size);
|
uint64_t chunk_size = MIN(bytes, s->cluster_size);
|
||||||
|
|
||||||
|
@ -64,6 +64,8 @@ struct XenBlockDataPlane {
|
|||||||
AioContext *ctx;
|
AioContext *ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int xen_block_send_response(XenBlockRequest *request);
|
||||||
|
|
||||||
static void reset_request(XenBlockRequest *request)
|
static void reset_request(XenBlockRequest *request)
|
||||||
{
|
{
|
||||||
memset(&request->req, 0, sizeof(request->req));
|
memset(&request->req, 0, sizeof(request->req));
|
||||||
@ -115,23 +117,26 @@ out:
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_block_finish_request(XenBlockRequest *request)
|
static void xen_block_complete_request(XenBlockRequest *request)
|
||||||
{
|
{
|
||||||
XenBlockDataPlane *dataplane = request->dataplane;
|
XenBlockDataPlane *dataplane = request->dataplane;
|
||||||
|
|
||||||
|
if (xen_block_send_response(request)) {
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
xen_device_notify_event_channel(dataplane->xendev,
|
||||||
|
dataplane->event_channel,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report_err(local_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QLIST_REMOVE(request, list);
|
QLIST_REMOVE(request, list);
|
||||||
dataplane->requests_inflight--;
|
dataplane->requests_inflight--;
|
||||||
}
|
|
||||||
|
|
||||||
static void xen_block_release_request(XenBlockRequest *request)
|
|
||||||
{
|
|
||||||
XenBlockDataPlane *dataplane = request->dataplane;
|
|
||||||
|
|
||||||
QLIST_REMOVE(request, list);
|
|
||||||
reset_request(request);
|
reset_request(request);
|
||||||
request->dataplane = dataplane;
|
request->dataplane = dataplane;
|
||||||
QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
|
QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
|
||||||
dataplane->requests_inflight--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -246,7 +251,6 @@ static int xen_block_copy_request(XenBlockRequest *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int xen_block_do_aio(XenBlockRequest *request);
|
static int xen_block_do_aio(XenBlockRequest *request);
|
||||||
static int xen_block_send_response(XenBlockRequest *request);
|
|
||||||
|
|
||||||
static void xen_block_complete_aio(void *opaque, int ret)
|
static void xen_block_complete_aio(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
@ -286,7 +290,6 @@ static void xen_block_complete_aio(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||||
xen_block_finish_request(request);
|
|
||||||
|
|
||||||
switch (request->req.operation) {
|
switch (request->req.operation) {
|
||||||
case BLKIF_OP_WRITE:
|
case BLKIF_OP_WRITE:
|
||||||
@ -306,17 +309,8 @@ static void xen_block_complete_aio(void *opaque, int ret)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xen_block_send_response(request)) {
|
|
||||||
Error *local_err = NULL;
|
|
||||||
|
|
||||||
xen_device_notify_event_channel(dataplane->xendev,
|
xen_block_complete_request(request);
|
||||||
dataplane->event_channel,
|
|
||||||
&local_err);
|
|
||||||
if (local_err) {
|
|
||||||
error_report_err(local_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xen_block_release_request(request);
|
|
||||||
|
|
||||||
if (dataplane->more_work) {
|
if (dataplane->more_work) {
|
||||||
qemu_bh_schedule(dataplane->bh);
|
qemu_bh_schedule(dataplane->bh);
|
||||||
@ -420,8 +414,8 @@ static int xen_block_do_aio(XenBlockRequest *request)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
xen_block_finish_request(request);
|
|
||||||
request->status = BLKIF_RSP_ERROR;
|
request->status = BLKIF_RSP_ERROR;
|
||||||
|
xen_block_complete_request(request);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,17 +569,7 @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (xen_block_send_response(request)) {
|
xen_block_complete_request(request);
|
||||||
Error *local_err = NULL;
|
|
||||||
|
|
||||||
xen_device_notify_event_channel(dataplane->xendev,
|
|
||||||
dataplane->event_channel,
|
|
||||||
&local_err);
|
|
||||||
if (local_err) {
|
|
||||||
error_report_err(local_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xen_block_release_request(request);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1924,8 +1924,8 @@ retry:
|
|||||||
if (status == BLK_DATA && !copy_range) {
|
if (status == BLK_DATA && !copy_range) {
|
||||||
ret = convert_co_read(s, sector_num, n, buf);
|
ret = convert_co_read(s, sector_num, n, buf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("error while reading sector %" PRId64
|
error_report("error while reading at byte %lld: %s",
|
||||||
": %s", sector_num, strerror(-ret));
|
sector_num * BDRV_SECTOR_SIZE, strerror(-ret));
|
||||||
s->ret = ret;
|
s->ret = ret;
|
||||||
}
|
}
|
||||||
} else if (!s->min_sparse && status == BLK_ZERO) {
|
} else if (!s->min_sparse && status == BLK_ZERO) {
|
||||||
@ -1953,8 +1953,8 @@ retry:
|
|||||||
ret = convert_co_write(s, sector_num, n, buf, status);
|
ret = convert_co_write(s, sector_num, n, buf, status);
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("error while writing sector %" PRId64
|
error_report("error while writing at byte %lld: %s",
|
||||||
": %s", sector_num, strerror(-ret));
|
sector_num * BDRV_SECTOR_SIZE, strerror(-ret));
|
||||||
s->ret = ret;
|
s->ret = ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,8 +193,8 @@ echo "== Verify image content =="
|
|||||||
verify_io()
|
verify_io()
|
||||||
{
|
{
|
||||||
if ($QEMU_IMG info -U -f "$IMGFMT" "$TEST_IMG" | grep "compat: 0.10" > /dev/null); then
|
if ($QEMU_IMG info -U -f "$IMGFMT" "$TEST_IMG" | grep "compat: 0.10" > /dev/null); then
|
||||||
# For v2 images, discarded clusters are read from the backing file
|
# In v2 images clusters are not discarded when there is a backing file.
|
||||||
# Keep the variable empty so that the backing file value can be used as
|
# Keep the variable empty so that the previous value can be used as
|
||||||
# the default below
|
# the default below
|
||||||
discarded=
|
discarded=
|
||||||
else
|
else
|
||||||
@ -230,14 +230,16 @@ verify_io()
|
|||||||
echo read -P 70 0x78000 0x6000
|
echo read -P 70 0x78000 0x6000
|
||||||
echo read -P 7 0x7e000 0x2000
|
echo read -P 7 0x7e000 0x2000
|
||||||
|
|
||||||
echo read -P ${discarded:-8} 0x80000 0x6000
|
echo read -P ${discarded:-89} 0x80000 0x1000
|
||||||
|
echo read -P ${discarded:-8} 0x81000 0x5000
|
||||||
echo read -P 80 0x86000 0x2000
|
echo read -P 80 0x86000 0x2000
|
||||||
echo read -P ${discarded:-8} 0x88000 0x2000
|
echo read -P ${discarded:-8} 0x88000 0x2000
|
||||||
echo read -P 81 0x8a000 0xe000
|
echo read -P 81 0x8a000 0xe000
|
||||||
echo read -P 90 0x98000 0x6000
|
echo read -P 90 0x98000 0x6000
|
||||||
echo read -P 9 0x9e000 0x2000
|
echo read -P 9 0x9e000 0x2000
|
||||||
|
|
||||||
echo read -P ${discarded:-10} 0xa0000 0x6000
|
echo read -P ${discarded:-109} 0xa0000 0x1000
|
||||||
|
echo read -P ${discarded:-10} 0xa1000 0x5000
|
||||||
echo read -P 100 0xa6000 0x2000
|
echo read -P 100 0xa6000 0x2000
|
||||||
echo read -P ${discarded:-10} 0xa8000 0x2000
|
echo read -P ${discarded:-10} 0xa8000 0x2000
|
||||||
echo read -P 101 0xaa000 0xe000
|
echo read -P 101 0xaa000 0xe000
|
||||||
|
@ -187,8 +187,10 @@ read 24576/24576 bytes at offset 491520
|
|||||||
24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 8192/8192 bytes at offset 516096
|
read 8192/8192 bytes at offset 516096
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 24576/24576 bytes at offset 524288
|
read 4096/4096 bytes at offset 524288
|
||||||
24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 20480/20480 bytes at offset 528384
|
||||||
|
20 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 8192/8192 bytes at offset 548864
|
read 8192/8192 bytes at offset 548864
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 8192/8192 bytes at offset 557056
|
read 8192/8192 bytes at offset 557056
|
||||||
@ -199,8 +201,10 @@ read 24576/24576 bytes at offset 622592
|
|||||||
24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 8192/8192 bytes at offset 647168
|
read 8192/8192 bytes at offset 647168
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 24576/24576 bytes at offset 655360
|
read 4096/4096 bytes at offset 655360
|
||||||
24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 20480/20480 bytes at offset 659456
|
||||||
|
20 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 8192/8192 bytes at offset 679936
|
read 8192/8192 bytes at offset 679936
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 8192/8192 bytes at offset 688128
|
read 8192/8192 bytes at offset 688128
|
||||||
|
@ -160,18 +160,16 @@ TEST_IMG=$BACKING_IMG _make_test_img 1G
|
|||||||
|
|
||||||
$QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
|
$QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
# compat=0.10 is required in order to make the following discard actually
|
_make_test_img -b "$BACKING_IMG" 1G
|
||||||
# unallocate the sector rather than make it a zero sector - we want COW, after
|
|
||||||
# all.
|
|
||||||
_make_test_img -o 'compat=0.10' -b "$BACKING_IMG" 1G
|
|
||||||
# Write two clusters, the second one enforces creation of an L2 table after
|
# Write two clusters, the second one enforces creation of an L2 table after
|
||||||
# the first data cluster.
|
# the first data cluster.
|
||||||
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
|
||||||
# Discard the first cluster. This cluster will soon enough be reallocated and
|
# Free the first cluster. This cluster will soon enough be reallocated and
|
||||||
# used for COW.
|
# used for COW.
|
||||||
$QEMU_IO -c 'discard 0k 64k' "$TEST_IMG" | _filter_qemu_io
|
poke_file "$TEST_IMG" "$l2_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
poke_file "$TEST_IMG" "$(($rb_offset+10))" "\x00\x00"
|
||||||
# Now, corrupt the image by marking the second L2 table cluster as free.
|
# Now, corrupt the image by marking the second L2 table cluster as free.
|
||||||
poke_file "$TEST_IMG" '131084' "\x00\x00" # 0x2000c
|
poke_file "$TEST_IMG" "$(($rb_offset+12))" "\x00\x00"
|
||||||
# Start a write operation requiring COW on the image stopping it right before
|
# Start a write operation requiring COW on the image stopping it right before
|
||||||
# doing the read; then, trigger the corruption prevention by writing anything to
|
# doing the read; then, trigger the corruption prevention by writing anything to
|
||||||
# any unallocated cluster, leading to an attempt to overwrite the second L2
|
# any unallocated cluster, leading to an attempt to overwrite the second L2
|
||||||
|
@ -105,8 +105,6 @@ wrote 65536/65536 bytes at offset 0
|
|||||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
wrote 65536/65536 bytes at offset 536870912
|
wrote 65536/65536 bytes at offset 536870912
|
||||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
discard 65536/65536 bytes at offset 0
|
|
||||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L2 table); further corruption events will be suppressed
|
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L2 table); further corruption events will be suppressed
|
||||||
blkdebug: Suspended request '0'
|
blkdebug: Suspended request '0'
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
@ -89,8 +89,9 @@ verify_io()
|
|||||||
{
|
{
|
||||||
if ($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" |
|
if ($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" |
|
||||||
grep "compat: 0.10" > /dev/null); then
|
grep "compat: 0.10" > /dev/null); then
|
||||||
# For v2 images, discarded clusters are read from the backing file
|
# In v2 images clusters are not discarded when there is a backing file
|
||||||
discarded=11
|
# so the previous value is read
|
||||||
|
discarded=22
|
||||||
else
|
else
|
||||||
# Discarded clusters are zeroed for v3 or later
|
# Discarded clusters are zeroed for v3 or later
|
||||||
discarded=0
|
discarded=0
|
||||||
|
@ -33,7 +33,7 @@ Convert to compressed target with data file:
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT.src', fmt=IMGFMT size=67108864
|
Formatting 'TEST_DIR/t.IMGFMT.src', fmt=IMGFMT size=67108864
|
||||||
wrote 1048576/1048576 bytes at offset 0
|
wrote 1048576/1048576 bytes at offset 0
|
||||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
qemu-img: error while writing sector 0: Operation not supported
|
qemu-img: error while writing at byte 0: Operation not supported
|
||||||
|
|
||||||
Convert uncompressed, then write compressed data manually:
|
Convert uncompressed, then write compressed data manually:
|
||||||
Images are identical.
|
Images are identical.
|
||||||
|
97
tests/qemu-iotests/290
Executable file
97
tests/qemu-iotests/290
Executable file
@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Test how 'qemu-io -c discard' behaves on v2 and v3 qcow2 images
|
||||||
|
#
|
||||||
|
# Copyright (C) 2020 Igalia, S.L.
|
||||||
|
# Author: Alberto Garcia <berto@igalia.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# creator
|
||||||
|
owner=berto@igalia.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
|
||||||
|
_supported_fmt qcow2
|
||||||
|
_supported_proto file
|
||||||
|
_supported_os Linux
|
||||||
|
_unsupported_imgopts 'compat=0.10' refcount_bits data_file
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "### Test 'qemu-io -c discard' on a QCOW2 image without a backing file"
|
||||||
|
echo
|
||||||
|
for qcow2_compat in 0.10 1.1; do
|
||||||
|
echo "# Create an image with compat=$qcow2_compat without a backing file"
|
||||||
|
_make_test_img -o "compat=$qcow2_compat" 128k
|
||||||
|
|
||||||
|
echo "# Fill all clusters with data and then discard them"
|
||||||
|
$QEMU_IO -c 'write -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'discard 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
echo "# Read the data from the discarded clusters"
|
||||||
|
$QEMU_IO -c 'read -P 0x00 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
echo "# Output of qemu-img map"
|
||||||
|
$QEMU_IMG map "$TEST_IMG" | _filter_testdir
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "### Test 'qemu-io -c discard' on a QCOW2 image with a backing file"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "# Create a backing image and fill it with data"
|
||||||
|
BACKING_IMG="$TEST_IMG.base"
|
||||||
|
TEST_IMG="$BACKING_IMG" _make_test_img 128k
|
||||||
|
$QEMU_IO -c 'write -P 0xff 0 128k' "$BACKING_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
for qcow2_compat in 0.10 1.1; do
|
||||||
|
echo "# Create an image with compat=$qcow2_compat and a backing file"
|
||||||
|
_make_test_img -o "compat=$qcow2_compat" -b "$BACKING_IMG"
|
||||||
|
|
||||||
|
echo "# Fill all clusters with data and then discard them"
|
||||||
|
$QEMU_IO -c 'write -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'discard 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
echo "# Read the data from the discarded clusters"
|
||||||
|
if [ "$qcow2_compat" = "1.1" ]; then
|
||||||
|
# In qcow2 v3 clusters are zeroed (with QCOW_OFLAG_ZERO)
|
||||||
|
$QEMU_IO -c 'read -P 0x00 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
else
|
||||||
|
# In qcow2 v2 if there's a backing image we cannot zero the clusters
|
||||||
|
# without exposing the backing file data so discard does nothing
|
||||||
|
$QEMU_IO -c 'read -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "# Output of qemu-img map"
|
||||||
|
$QEMU_IMG map "$TEST_IMG" | _filter_testdir
|
||||||
|
done
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
61
tests/qemu-iotests/290.out
Normal file
61
tests/qemu-iotests/290.out
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
QA output created by 290
|
||||||
|
|
||||||
|
### Test 'qemu-io -c discard' on a QCOW2 image without a backing file
|
||||||
|
|
||||||
|
# Create an image with compat=0.10 without a backing file
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
|
||||||
|
# Fill all clusters with data and then discard them
|
||||||
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
discard 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Read the data from the discarded clusters
|
||||||
|
read 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Output of qemu-img map
|
||||||
|
Offset Length Mapped to File
|
||||||
|
# Create an image with compat=1.1 without a backing file
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
|
||||||
|
# Fill all clusters with data and then discard them
|
||||||
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
discard 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Read the data from the discarded clusters
|
||||||
|
read 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Output of qemu-img map
|
||||||
|
Offset Length Mapped to File
|
||||||
|
|
||||||
|
### Test 'qemu-io -c discard' on a QCOW2 image with a backing file
|
||||||
|
|
||||||
|
# Create a backing image and fill it with data
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=131072
|
||||||
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Create an image with compat=0.10 and a backing file
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base
|
||||||
|
# Fill all clusters with data and then discard them
|
||||||
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
discard 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Read the data from the discarded clusters
|
||||||
|
read 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Output of qemu-img map
|
||||||
|
Offset Length Mapped to File
|
||||||
|
0 0x20000 0x50000 TEST_DIR/t.qcow2
|
||||||
|
# Create an image with compat=1.1 and a backing file
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base
|
||||||
|
# Fill all clusters with data and then discard them
|
||||||
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
discard 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Read the data from the discarded clusters
|
||||||
|
read 131072/131072 bytes at offset 0
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
# Output of qemu-img map
|
||||||
|
Offset Length Mapped to File
|
||||||
|
*** done
|
@ -23,7 +23,7 @@ do_is_allocated() {
|
|||||||
local count=$4
|
local count=$4
|
||||||
|
|
||||||
for ((i=1;i<=$count;i++)); do
|
for ((i=1;i<=$count;i++)); do
|
||||||
echo alloc $(( start + (i - 1) * step )) $size
|
echo "alloc $(( start + (i - 1) * step )) $size"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,9 +39,9 @@ do_io() {
|
|||||||
local count=$5
|
local count=$5
|
||||||
local pattern=$6
|
local pattern=$6
|
||||||
|
|
||||||
echo === IO: pattern $pattern >&2
|
echo "=== IO: pattern $pattern" >&2
|
||||||
for ((i=1;i<=$count;i++)); do
|
for ((i=1;i<=$count;i++)); do
|
||||||
echo $op -P $pattern $(( start + (i - 1) * step )) $size
|
echo "$op -P $pattern $(( start + (i - 1) * step )) $size"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,31 +110,31 @@ io_test2() {
|
|||||||
# free - free - compressed
|
# free - free - compressed
|
||||||
|
|
||||||
# Write the clusters to be compressed
|
# Write the clusters to be compressed
|
||||||
echo === Clusters to be compressed [1]
|
echo '=== Clusters to be compressed [1]'
|
||||||
io_pattern writev $((offset + 4 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
io_pattern writev $((offset + 4 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
||||||
echo === Clusters to be compressed [2]
|
echo '=== Clusters to be compressed [2]'
|
||||||
io_pattern writev $((offset + 5 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
io_pattern writev $((offset + 5 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
||||||
echo === Clusters to be compressed [3]
|
echo '=== Clusters to be compressed [3]'
|
||||||
io_pattern writev $((offset + 8 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
io_pattern writev $((offset + 8 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
||||||
|
|
||||||
mv "$TEST_IMG" "$TEST_IMG.orig"
|
mv "$TEST_IMG" "$TEST_IMG.orig"
|
||||||
$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c "$TEST_IMG.orig" "$TEST_IMG"
|
$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c "$TEST_IMG.orig" "$TEST_IMG"
|
||||||
|
|
||||||
# Write the used clusters
|
# Write the used clusters
|
||||||
echo === Used clusters [1]
|
echo '=== Used clusters [1]'
|
||||||
io_pattern writev $((offset + 0 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
io_pattern writev $((offset + 0 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
||||||
echo === Used clusters [2]
|
echo '=== Used clusters [2]'
|
||||||
io_pattern writev $((offset + 1 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
io_pattern writev $((offset + 1 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
||||||
echo === Used clusters [3]
|
echo '=== Used clusters [3]'
|
||||||
io_pattern writev $((offset + 3 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
io_pattern writev $((offset + 3 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165
|
||||||
|
|
||||||
# Read them
|
# Read them
|
||||||
echo === Read used/compressed clusters
|
echo '=== Read used/compressed clusters'
|
||||||
io_pattern readv $((offset + 0 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num 165
|
io_pattern readv $((offset + 0 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num 165
|
||||||
io_pattern readv $((offset + 3 * $cluster_size)) $((3 * $cluster_size)) $((9 * $cluster_size)) $num 165
|
io_pattern readv $((offset + 3 * $cluster_size)) $((3 * $cluster_size)) $((9 * $cluster_size)) $num 165
|
||||||
io_pattern readv $((offset + 8 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num 165
|
io_pattern readv $((offset + 8 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num 165
|
||||||
|
|
||||||
echo === Read zeros
|
echo '=== Read zeros'
|
||||||
io_zero readv $((offset + 2 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num
|
io_zero readv $((offset + 2 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num
|
||||||
io_zero readv $((offset + 6 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num
|
io_zero readv $((offset + 6 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num
|
||||||
}
|
}
|
||||||
|
@ -296,3 +296,4 @@
|
|||||||
286 rw quick
|
286 rw quick
|
||||||
288 quick
|
288 quick
|
||||||
289 rw quick
|
289 rw quick
|
||||||
|
290 rw auto quick
|
||||||
|
Loading…
x
Reference in New Issue
Block a user