Skip to content

Commit

Permalink
Merge tag 'pull-block-2022-03-22' of https://gitlab.com/hreitz/qemu i…
Browse files Browse the repository at this point in the history
…nto staging

Block patches for 7.0-rc1:
- iotest fixes:
  - Fix some iotests for riscv targets
  - Use GNU sed in more places where required
  - Meson-related fixes (i.e. to print errors when they occur)
  - Have qemu-img calls (from Python tests) generally raise nicely
    formattable exceptions on errors
  - Fix iotest 207
- Allow RBD images to be growable by writing zeroes past the end of
  file, fixing qcow2 on rbd

# gpg: Signature made Tue 22 Mar 2022 11:51:10 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

* tag 'pull-block-2022-03-22' of https://gitlab.com/hreitz/qemu: (25 commits)
  iotests/207: Filter host fingerprint
  iotests.py: Filters for VM.run_job()
  iotests: make qemu_img_log and img_info_log raise on error
  iotests: remove qemu_img_pipe_and_status()
  iotests: replace qemu_img_log('create', ...) calls
  iotests: use qemu_img() in has_working_luks()
  iotests: remove remaining calls to qemu_img_pipe()
  iotests/149: Remove qemu_img_pipe() call
  iotests: replace unchecked calls to qemu_img_pipe()
  iotests: change supports_quorum to use qemu_img
  iotests: add qemu_img_map() function
  iotests/remove-bitmap-from-backing: use qemu_img_info()
  iotests: add qemu_img_info()
  iotests: use qemu_img_json() when applicable
  iotests: add qemu_img_json()
  iotests: fortify compare_images() against crashes
  iotests: make qemu_img raise on non-zero rc by default
  iotests: Remove explicit checks for qemu_img() == 0
  python/utils: add VerboseProcessError
  python/utils: add add_visual_margin() text decoration utility
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Mar 22, 2022
2 parents 5791de9 + 48f1fcd commit 9d36d5f
Show file tree
Hide file tree
Showing 50 changed files with 402 additions and 272 deletions.
26 changes: 14 additions & 12 deletions block/rbd.c
Expand Up @@ -1107,6 +1107,20 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,

assert(!qiov || qiov->size == bytes);

if (cmd == RBD_AIO_WRITE || cmd == RBD_AIO_WRITE_ZEROES) {
/*
* RBD APIs don't allow us to write more than actual size, so in order
* to support growing images, we resize the image before write
* operations that exceed the current size.
*/
if (offset + bytes > s->image_size) {
int r = qemu_rbd_resize(bs, offset + bytes);
if (r < 0) {
return r;
}
}
}

r = rbd_aio_create_completion(&task,
(rbd_callback_t) qemu_rbd_completion_cb, &c);
if (r < 0) {
Expand Down Expand Up @@ -1182,18 +1196,6 @@ coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
BDRVRBDState *s = bs->opaque;
/*
* RBD APIs don't allow us to write more than actual size, so in order
* to support growing images, we resize the image before write
* operations that exceed the current size.
*/
if (offset + bytes > s->image_size) {
int r = qemu_rbd_resize(bs, offset + bytes);
if (r < 0) {
return r;
}
}
return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_WRITE);
}

Expand Down
6 changes: 3 additions & 3 deletions meson.build
Expand Up @@ -3,9 +3,9 @@ project('qemu', ['c'], meson_version: '>=0.59.3',
'b_staticpic=false', 'stdsplit=false'],
version: files('VERSION'))

add_test_setup('quick', exclude_suites: ['block', 'slow', 'thorough'], is_default: true)
add_test_setup('slow', exclude_suites: ['block', 'thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow'])
add_test_setup('thorough', exclude_suites: ['block'], env: ['G_TEST_SLOW=1', 'SPEED=thorough'])
add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true)
add_test_setup('slow', exclude_suites: ['thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow'])
add_test_setup('thorough', env: ['G_TEST_SLOW=1', 'SPEED=thorough'])

not_found = dependency('', required: false)
keyval = import('keyval')
Expand Down
117 changes: 117 additions & 0 deletions python/qemu/utils/__init__.py
Expand Up @@ -15,14 +15,20 @@
# the COPYING file in the top-level directory.
#

import os
import re
import shutil
from subprocess import CalledProcessError
import textwrap
from typing import Optional

# pylint: disable=import-error
from .accel import kvm_available, list_accel, tcg_available


__all__ = (
'VerboseProcessError',
'add_visual_margin',
'get_info_usernet_hostfwd_port',
'kvm_available',
'list_accel',
Expand All @@ -43,3 +49,114 @@ def get_info_usernet_hostfwd_port(info_usernet_output: str) -> Optional[int]:
if match is not None:
return int(match[1])
return None


# pylint: disable=too-many-arguments
def add_visual_margin(
content: str = '',
width: Optional[int] = None,
name: Optional[str] = None,
padding: int = 1,
upper_left: str = '┏',
lower_left: str = '┗',
horizontal: str = '━',
vertical: str = '┃',
) -> str:
"""
Decorate and wrap some text with a visual decoration around it.
This function assumes that the text decoration characters are single
characters that display using a single monospace column.
┏━ Example ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ This is what this function looks like with text content that's
┃ wrapped to 66 characters. The right-hand margin is left open to
┃ accommodate the occasional unicode character that might make
┃ predicting the total "visual" width of a line difficult. This
┃ provides a visual distinction that's good-enough, though.
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
:param content: The text to wrap and decorate.
:param width:
The number of columns to use, including for the decoration
itself. The default (None) uses the the available width of the
current terminal, or a fallback of 72 lines. A negative number
subtracts a fixed-width from the default size. The default obeys
the COLUMNS environment variable, if set.
:param name: A label to apply to the upper-left of the box.
:param padding: How many columns of padding to apply inside.
:param upper_left: Upper-left single-width text decoration character.
:param lower_left: Lower-left single-width text decoration character.
:param horizontal: Horizontal single-width text decoration character.
:param vertical: Vertical single-width text decoration character.
"""
if width is None or width < 0:
avail = shutil.get_terminal_size(fallback=(72, 24))[0]
if width is None:
_width = avail
else:
_width = avail + width
else:
_width = width

prefix = vertical + (' ' * padding)

def _bar(name: Optional[str], top: bool = True) -> str:
ret = upper_left if top else lower_left
if name is not None:
ret += f"{horizontal} {name} "

filler_len = _width - len(ret)
ret += f"{horizontal * filler_len}"
return ret

def _wrap(line: str) -> str:
return os.linesep.join(
textwrap.wrap(
line, width=_width - padding, initial_indent=prefix,
subsequent_indent=prefix, replace_whitespace=False,
drop_whitespace=True, break_on_hyphens=False)
)

return os.linesep.join((
_bar(name, top=True),
os.linesep.join(_wrap(line) for line in content.splitlines()),
_bar(None, top=False),
))


class VerboseProcessError(CalledProcessError):
"""
The same as CalledProcessError, but more verbose.
This is useful for debugging failed calls during test executions.
The return code, signal (if any), and terminal output will be displayed
on unhandled exceptions.
"""
def summary(self) -> str:
"""Return the normal CalledProcessError str() output."""
return super().__str__()

def __str__(self) -> str:
lmargin = ' '
width = -len(lmargin)
sections = []

# Does self.stdout contain both stdout and stderr?
has_combined_output = self.stderr is None

name = 'output' if has_combined_output else 'stdout'
if self.stdout:
sections.append(add_visual_margin(self.stdout, width, name))
else:
sections.append(f"{name}: N/A")

if self.stderr:
sections.append(add_visual_margin(self.stderr, width, 'stderr'))
elif not has_combined_output:
sections.append("stderr: N/A")

return os.linesep.join((
self.summary(),
textwrap.indent(os.linesep.join(sections), prefix=lmargin),
))
4 changes: 0 additions & 4 deletions scripts/mtest2make.py
Expand Up @@ -101,10 +101,6 @@ def emit_suite(name, suite, prefix):
testsuites = defaultdict(Suite)
for test in introspect['tests']:
process_tests(test, targets, testsuites)
# HACK: check-block is a separate target so that it runs with --verbose;
# only write the dependencies
emit_suite_deps('block', testsuites['block'], 'check')
del testsuites['block']
emit_prolog(testsuites, 'check')
for name, suite in testsuites.items():
emit_suite(name, suite, 'check')
Expand Down
9 changes: 1 addition & 8 deletions tests/Makefile.include
Expand Up @@ -147,16 +147,9 @@ check-acceptance: check-acceptance-deprecated-warning | check-avocado

# Consolidated targets

.PHONY: check-block check check-clean get-vm-images
.PHONY: check check-clean get-vm-images
check:

ifneq ($(.check-block.deps),)
check: check-block
check-block: run-ninja
$(if $(MAKE.n),,+)$(MESON) test $(MTESTARGS) $(.mtestargs) --verbose \
--logbase iotestslog $(call .speed.$(SPEED), block block-slow block-thorough)
endif

check-build: run-ninja

check-clean:
Expand Down
5 changes: 2 additions & 3 deletions tests/qemu-iotests/041
Expand Up @@ -24,7 +24,7 @@ import os
import re
import json
import iotests
from iotests import qemu_img, qemu_img_pipe, qemu_io
from iotests import qemu_img, qemu_img_map, qemu_io

backing_img = os.path.join(iotests.test_dir, 'backing.img')
target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
Expand Down Expand Up @@ -1360,8 +1360,7 @@ class TestFilters(iotests.QMPTestCase):

self.vm.qmp('blockdev-del', node_name='target')

target_map = qemu_img_pipe('map', '--output=json', target_img)
target_map = json.loads(target_map)
target_map = qemu_img_map(target_img)

assert target_map[0]['start'] == 0
assert target_map[0]['length'] == 512 * 1024
Expand Down
7 changes: 3 additions & 4 deletions tests/qemu-iotests/065
Expand Up @@ -24,7 +24,7 @@ import os
import re
import json
import iotests
from iotests import qemu_img, qemu_img_pipe
from iotests import qemu_img, qemu_img_info
import unittest

test_img = os.path.join(iotests.test_dir, 'test.img')
Expand All @@ -49,13 +49,12 @@ class TestQemuImgInfo(TestImageInfoSpecific):
human_compare = None

def test_json(self):
data = json.loads(qemu_img_pipe('info', '--output=json', test_img))
data = data['format-specific']
data = qemu_img_info(test_img)['format-specific']
self.assertEqual(data['type'], iotests.imgfmt)
self.assertEqual(data['data'], self.json_compare)

def test_human(self):
data = qemu_img_pipe('info', '--output=human', test_img).split('\n')
data = qemu_img('info', '--output=human', test_img).stdout.split('\n')
data = data[(data.index('Format specific information:') + 1)
:data.index('')]
for field in data:
Expand Down
7 changes: 5 additions & 2 deletions tests/qemu-iotests/149
Expand Up @@ -265,8 +265,11 @@ def qemu_img_create(config, size_mb):
"%dM" % size_mb]

iotests.log("qemu-img " + " ".join(args), filters=[iotests.filter_test_dir])
iotests.log(check_cipher_support(config, iotests.qemu_img_pipe(*args)),
filters=[iotests.filter_test_dir])
try:
iotests.qemu_img(*args)
except subprocess.CalledProcessError as exc:
check_cipher_support(config, exc.output)
raise

def qemu_io_image_args(config, dev=False):
"""Get the args for access an image or device with qemu-io"""
Expand Down

0 comments on commit 9d36d5f

Please sign in to comment.