Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/hreitz-gitlab/tags/pull-block-2…
Browse files Browse the repository at this point in the history
…022-02-01' into staging

Block patches:
- Add support to the iotests to test qcow2's zstd compression mode
- Fix post-migration block node permissions
- iotests fixes (051 and mirror-ready-cancel-error)
- Remove an outdated comment

# gpg: Signature made Tue 01 Feb 2022 13:34:54 GMT
# gpg:                using RSA key CB62D7A0EE3829E45F004D34A1FA40D098019CDF
# gpg:                issuer "hreitz@redhat.com"
# gpg: Good signature from "Hanna Reitz <hreitz@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: CB62 D7A0 EE38 29E4 5F00  4D34 A1FA 40D0 9801 9CDF

* remotes/hreitz-gitlab/tags/pull-block-2022-02-01: (24 commits)
  block.h: remove outdated comment
  iotests/migration-permissions: New test
  block-backend: Retain permissions after migration
  iotests: declare lack of support for compresion_type in IMGOPTS
  iotest 214: explicit compression type
  iotests 60: more accurate set dirty bit in qcow2 header
  iotests: bash tests: filter compression type
  iotest 39: use _qcow2_dump_header
  iotests: massive use _qcow2_dump_header
  iotests/common.rc: introduce _qcow2_dump_header helper
  qcow2: simple case support for downgrading of qcow2 images with zstd
  iotest 302: use img_info_log() helper
  iotests.py: filter compression type out
  iotests.py: filter out successful output of qemu-img create
  iotest 065: explicit compression type
  iotest 303: explicit compression type
  iotests.py: rewrite default luks support in qemu_img
  iotests: drop qemu_img_verbose() helper
  iotests.py: qemu_img*("create"): support IMGOPTS='compression_type=zstd'
  iotests: specify some unsupported_imgopts for python iotests
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Feb 1, 2022
2 parents 5cbe641 + 751486c commit 3bbe296
Show file tree
Hide file tree
Showing 54 changed files with 483 additions and 236 deletions.
11 changes: 11 additions & 0 deletions block/block-backend.c
Expand Up @@ -190,19 +190,30 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
{
BlockBackend *blk = child->opaque;
Error *local_err = NULL;
uint64_t saved_shared_perm;

if (!blk->disable_perm) {
return;
}

blk->disable_perm = false;

/*
* blk->shared_perm contains the permissions we want to share once
* migration is really completely done. For now, we need to share
* all; but we also need to retain blk->shared_perm, which is
* overwritten by a successful blk_set_perm() call. Save it and
* restore it below.
*/
saved_shared_perm = blk->shared_perm;

blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
blk->disable_perm = true;
return;
}
blk->shared_perm = saved_shared_perm;

if (runstate_check(RUN_STATE_INMIGRATE)) {
/* Activation can happen when migration process is still active, for
Expand Down
58 changes: 56 additions & 2 deletions block/qcow2.c
Expand Up @@ -5279,6 +5279,38 @@ static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
}

static int qcow2_has_compressed_clusters(BlockDriverState *bs)
{
int64_t offset = 0;
int64_t bytes = bdrv_getlength(bs);

if (bytes < 0) {
return bytes;
}

while (bytes != 0) {
int ret;
QCow2SubclusterType type;
unsigned int cur_bytes = MIN(INT_MAX, bytes);
uint64_t host_offset;

ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset,
&type);
if (ret < 0) {
return ret;
}

if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
return 1;
}

offset += cur_bytes;
bytes -= cur_bytes;
}

return 0;
}

/*
* Downgrades an image's version. To achieve this, any incompatible features
* have to be removed.
Expand Down Expand Up @@ -5336,9 +5368,10 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
* the first place; if that happens nonetheless, returning -ENOTSUP is the
* best thing to do anyway */

if (s->incompatible_features) {
if (s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION) {
error_setg(errp, "Cannot downgrade an image with incompatible features "
"%#" PRIx64 " set", s->incompatible_features);
"0x%" PRIx64 " set",
s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION);
return -ENOTSUP;
}

Expand All @@ -5356,6 +5389,27 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
return ret;
}

if (s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION) {
ret = qcow2_has_compressed_clusters(bs);
if (ret < 0) {
error_setg(errp, "Failed to check block status");
return -EINVAL;
}
if (ret) {
error_setg(errp, "Cannot downgrade an image with zstd compression "
"type and existing compressed clusters");
return -ENOTSUP;
}
/*
* No compressed clusters for now, so just chose default zlib
* compression.
*/
s->incompatible_features &= ~QCOW2_INCOMPAT_COMPRESSION;
s->compression_type = QCOW2_COMPRESSION_TYPE_ZLIB;
}

assert(s->incompatible_features == 0);

s->qcow_version = target_version;
ret = qcow2_update_header(bs);
if (ret < 0) {
Expand Down
1 change: 0 additions & 1 deletion include/block/block.h
Expand Up @@ -344,7 +344,6 @@ typedef unsigned int BdrvChildRole;
char *bdrv_perm_names(uint64_t perm);
uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);

/* disk I/O throttling */
void bdrv_init(void);
void bdrv_init_with_whitelist(void);
bool bdrv_uses_whitelist(void);
Expand Down
11 changes: 6 additions & 5 deletions tests/qemu-iotests/031
Expand Up @@ -42,8 +42,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file fuse
# We want to test compat=0.10, which does not support external data
# files or refcount widths other than 16
_unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
# files or refcount widths other than 16 or compression type
_unsupported_imgopts data_file compression_type \
'refcount_bits=\([^1]\|.\([^6]\|$\)\)'

CLUSTER_SIZE=65536

Expand All @@ -58,21 +59,21 @@ for compat in "compat=0.10" "compat=1.1"; do
echo
_make_test_img -o $compat 64M
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
$PYTHON qcow2.py "$TEST_IMG" dump-header
_qcow2_dump_header
_check_test_img

echo
echo === Rewrite header with no backing file ===
echo
$QEMU_IMG rebase -u -b "" "$TEST_IMG"
$PYTHON qcow2.py "$TEST_IMG" dump-header
_qcow2_dump_header
_check_test_img

echo
echo === Add a backing file and format ===
echo
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG"
$PYTHON qcow2.py "$TEST_IMG" dump-header
_qcow2_dump_header
done

# success, all done
Expand Down
6 changes: 3 additions & 3 deletions tests/qemu-iotests/036
Expand Up @@ -58,7 +58,7 @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63

# Without feature table
$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
_qcow2_dump_header | grep features
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
_img_info

Expand Down Expand Up @@ -107,15 +107,15 @@ echo === Create image with unknown autoclear feature bit ===
echo
_make_test_img 64M
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
_qcow2_dump_header | grep features
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts

echo
echo === Repair image ===
echo
_check_test_img -r all

$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
_qcow2_dump_header | grep features
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts

# success, all done
Expand Down
22 changes: 11 additions & 11 deletions tests/qemu-iotests/039
Expand Up @@ -59,7 +59,7 @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" $size
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io

# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_check_test_img

echo
Expand All @@ -73,7 +73,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
| _filter_qemu_io

# The dirty bit must be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_check_test_img

echo
Expand All @@ -82,15 +82,15 @@ echo "== Read-only access must still work =="
$QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io

# The dirty bit must be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

echo
echo "== Repairing the image file must succeed =="

_check_test_img -r all

# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

echo
echo "== Data should still be accessible after repair =="
Expand All @@ -108,12 +108,12 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
| _filter_qemu_io

# The dirty bit must be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io

# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

echo
echo "== Creating an image file with lazy_refcounts=off =="
Expand All @@ -126,7 +126,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
| _filter_qemu_io

# The dirty bit must not be set since lazy_refcounts=off
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_check_test_img

echo
Expand All @@ -141,8 +141,8 @@ $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG commit "$TEST_IMG"

# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_qcow2_dump_header "$TEST_IMG".base | grep incompatible_features

_check_test_img
TEST_IMG="$TEST_IMG".base _check_test_img
Expand All @@ -159,7 +159,7 @@ $QEMU_IO -c "reopen -o lazy-refcounts=on" \
| _filter_qemu_io

# The dirty bit must be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_check_test_img

_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
Expand All @@ -171,7 +171,7 @@ $QEMU_IO -c "reopen -o lazy-refcounts=off" \
| _filter_qemu_io

# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_check_test_img


Expand Down
8 changes: 5 additions & 3 deletions tests/qemu-iotests/044
Expand Up @@ -24,7 +24,7 @@ import os
import qcow2
from qcow2 import QcowHeader
import iotests
from iotests import qemu_img, qemu_img_verbose, qemu_io
from iotests import qemu_img, qemu_img_log, qemu_io
import struct
import subprocess
import sys
Expand Down Expand Up @@ -112,9 +112,11 @@ class TestRefcountTableGrowth(iotests.QMPTestCase):

def test_grow_refcount_table(self):
qemu_io('-c', 'write 3800M 1M', test_img)
qemu_img_verbose('check' , test_img)
qemu_img_log('check' , test_img)
pass

if __name__ == '__main__':
iotests.activate_logging()
iotests.main(supported_fmts=['qcow2'],
supported_protocols=['file'])
supported_protocols=['file'],
unsupported_imgopts=['refcount_bits'])
1 change: 1 addition & 0 deletions tests/qemu-iotests/044.out
@@ -1,6 +1,7 @@
No errors were found on the image.
7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
Image end offset: 4296217088

.
----------------------------------------------------------------------
Ran 1 tests
Expand Down
9 changes: 7 additions & 2 deletions tests/qemu-iotests/051
Expand Up @@ -41,10 +41,15 @@ _supported_fmt qcow2
_supported_proto file
# A compat=0.10 image is created in this test which does not support anything
# other than refcount_bits=16;
# it also will not support an external data file
_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
# it also will not support an external data file and compression type
_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file \
compression_type
_require_drivers nbd

if [ "$QEMU_DEFAULT_MACHINE" = "pc" ]; then
_require_devices lsi53c895a
fi

do_run_qemu()
{
echo Testing: "$@"
Expand Down
22 changes: 11 additions & 11 deletions tests/qemu-iotests/060
Expand Up @@ -80,13 +80,13 @@ poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00"
_check_test_img

# The corrupt bit should not be set anyway
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

# Try to write something, thereby forcing the corrupt bit to be set
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io

# The corrupt bit must now be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

# This information should be available through qemu-img info
_img_info --format-specific
Expand Down Expand Up @@ -114,19 +114,19 @@ poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01"
# Redirect new data cluster onto refcount block
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
_check_test_img
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

# Try to fix it
_check_test_img -r all

# The corrupt bit should be cleared
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

# Look if it's really really fixed
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

echo
echo "=== Testing cluster data reference into inactive L2 table ==="
Expand All @@ -139,13 +139,13 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
"\x80\x00\x00\x00\x00\x04\x00\x00"
_check_test_img
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
_check_test_img -r all
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features
$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_qcow2_dump_header | grep incompatible_features

# Check data
$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
Expand Down Expand Up @@ -326,7 +326,7 @@ _make_test_img 64M
# Let the refblock appear unaligned
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\xff\xff\x2a\x00"
# Mark the image dirty, thus forcing an automatic check when opening it
poke_file "$TEST_IMG" 72 "\x00\x00\x00\x00\x00\x00\x00\x01"
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 0
# Open the image (qemu should refuse to do so)
$QEMU_IO -c close "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt

Expand Down
2 changes: 1 addition & 1 deletion tests/qemu-iotests/060.out
Expand Up @@ -17,7 +17,7 @@ virtual size: 64 MiB (67108864 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
compression type: COMPRESSION_TYPE
lazy refcounts: false
refcount bits: 16
corrupt: true
Expand Down

0 comments on commit 3bbe296

Please sign in to comment.