Block layer patches

- Expose block limits in monitor and qemu-img info
 - Resize: Refresh filter node size when its child was resized
 - Support configuring stats-intervals in -device (instead of only -drive)
 - luks: Fix QMP x-blockdev-amend crash and image creation with detached-header
 - iotests: Several test case fixes
 - Code cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmkCAkIRHGt3b2xmQHJl
 ZGhhdC5jb20ACgkQfwmycsiPL9a3bA/+MMS9ocOyEiE4u66XbhQ4KgqxECtD/uzg
 3lYQJbfVpphizq0QQn1pAno9rpjdWnkwPv9TasAEM/9R/wz/ygjmXM9GyQDvNLoB
 t6dTyWKpsi4lVB7FNPBNQvyz7mHqWQULrhI/mNGLsbiss32SMiE08amjOzSrFSZJ
 zn8TsEzDB218Bv8OBH/eI1mMvZ2gG6+yzPf7znA5nSOtJkG1kGLPInZuRgeN7e7W
 DUl5EeiP3sGZh4pF/IyRc8BNMsvPR7Lk31PrPEXAz+7g0y8dfPukrcR0nY6nwekT
 omPhbIBfDOEKpYdBxheOdh9TkT40Fo2Oc7DIhzY4at3O02BKy60kJSZaqoWj+80L
 A3yJ1K7wgiwqzOw0VaHU56Y5awnD5cculciwHxrfc6OHnG9cotvCSxsU2qr/UMd2
 N/cPhUDKfWcilVoRNy+yYiubQsp2s4amF2uGDn/QjjZx0c3dgfXc9BCNmu9nbAMr
 UsmzZBH9GCpaTajVIsX8RdnaovMTxGr4UFyuSQ2jWYWp3k2BR89jkBpXReGGOYr6
 SuEOOnx/E1duTZUPq1gdSkQm9uGxxq5FSGIWR+rWMdFkZS09HStmq5hcY+Zx0pSg
 JzDaLgPATV65y0VswFVUj6NemmNU983DwKPACwVCpemeBETtVuoU/CydzEPPwiL6
 Kl5ISmjZz3I=
 =v2BI
 -----END PGP SIGNATURE-----

Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging

Block layer patches

- Expose block limits in monitor and qemu-img info
- Resize: Refresh filter node size when its child was resized
- Support configuring stats-intervals in -device (instead of only -drive)
- luks: Fix QMP x-blockdev-amend crash and image creation with detached-header
- iotests: Several test case fixes
- Code cleanups

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCgAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmkCAkIRHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9a3bA/+MMS9ocOyEiE4u66XbhQ4KgqxECtD/uzg
# 3lYQJbfVpphizq0QQn1pAno9rpjdWnkwPv9TasAEM/9R/wz/ygjmXM9GyQDvNLoB
# t6dTyWKpsi4lVB7FNPBNQvyz7mHqWQULrhI/mNGLsbiss32SMiE08amjOzSrFSZJ
# zn8TsEzDB218Bv8OBH/eI1mMvZ2gG6+yzPf7znA5nSOtJkG1kGLPInZuRgeN7e7W
# DUl5EeiP3sGZh4pF/IyRc8BNMsvPR7Lk31PrPEXAz+7g0y8dfPukrcR0nY6nwekT
# omPhbIBfDOEKpYdBxheOdh9TkT40Fo2Oc7DIhzY4at3O02BKy60kJSZaqoWj+80L
# A3yJ1K7wgiwqzOw0VaHU56Y5awnD5cculciwHxrfc6OHnG9cotvCSxsU2qr/UMd2
# N/cPhUDKfWcilVoRNy+yYiubQsp2s4amF2uGDn/QjjZx0c3dgfXc9BCNmu9nbAMr
# UsmzZBH9GCpaTajVIsX8RdnaovMTxGr4UFyuSQ2jWYWp3k2BR89jkBpXReGGOYr6
# SuEOOnx/E1duTZUPq1gdSkQm9uGxxq5FSGIWR+rWMdFkZS09HStmq5hcY+Zx0pSg
# JzDaLgPATV65y0VswFVUj6NemmNU983DwKPACwVCpemeBETtVuoU/CydzEPPwiL6
# Kl5ISmjZz3I=
# =v2BI
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 29 Oct 2025 01:02:10 PM CET
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* tag 'for-upstream' of https://repo.or.cz/qemu/kevin:
  qemu-img info: Add cache mode option
  qemu-img info: Optionally show block limits
  block: Expose block limits for images in QMP
  block: Improve comments in BlockLimits
  iotests: add test for resizing a 'file' node below a 'raw' node
  iotests: add test for resizing a node below filters
  block: implement 'resize' callback for child_of_bds class
  block: make bdrv_co_parent_cb_resize() a proper IO API function
  include/block/block_int-common: document when resize callback is used
  MAINTAINERS: Mark VHDX block driver as "Odd Fixes"
  block: enable stats-intervals for storage devices
  iotests: Adjust fuse-allow-other expected output
  iotests: Adjust nbd expected outputs to match current behavior
  block/curl.c: Fix CURLOPT_VERBOSE parameter type
  block/monitor: Use hmp_handle_error to report error
  block: fix luks 'amend' when run in coroutine
  block: remove 'detached-header' option from opts after use
  tests/qemu-iotests: Mark the 'inactive-node-nbd' as unsupported with -luks

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2025-10-30 09:24:15 +01:00
commit 0979667049
32 changed files with 479 additions and 96 deletions

View file

@ -4081,7 +4081,7 @@ F: block/rbd.c
VHDX
M: Jeff Cody <codyprime@gmail.com>
L: qemu-block@nongnu.org
S: Supported
S: Odd Fixes
F: block/vhdx*
VDI

12
block.c
View file

@ -1497,6 +1497,17 @@ static void GRAPH_WRLOCK bdrv_child_cb_detach(BdrvChild *child)
}
}
static void coroutine_fn GRAPH_RDLOCK bdrv_child_cb_resize(BdrvChild *child)
{
BlockDriverState *bs = child->opaque;
if (child->role & BDRV_CHILD_FILTERED) {
/* Best effort, ignore errors. */
bdrv_co_refresh_total_sectors(bs, bs->total_sectors);
bdrv_co_parent_cb_resize(bs);
}
}
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
const char *filename,
bool backing_mask_protocol,
@ -1529,6 +1540,7 @@ const BdrvChildClass child_of_bds = {
.detach = bdrv_child_cb_detach,
.inactivate = bdrv_child_cb_inactivate,
.change_aio_ctx = bdrv_child_cb_change_aio_ctx,
.resize = bdrv_child_cb_resize,
.update_filename = bdrv_child_cb_update_filename,
.get_parent_aio_context = child_of_bds_get_parent_aio_context,
};

View file

@ -28,6 +28,7 @@
#include "block/block_int.h"
#include "qemu/timer.h"
#include "system/qtest.h"
#include "qapi/error.h"
static QEMUClockType clock_type = QEMU_CLOCK_REALTIME;
static const int qtest_latency_ns = NANOSECONDS_PER_SECOND / 1000;
@ -56,13 +57,25 @@ static bool bool_from_onoffauto(OnOffAuto val, bool def)
}
}
void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
enum OnOffAuto account_failed)
bool block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
enum OnOffAuto account_failed, uint32_t *stats_intervals,
uint32_t num_stats_intervals, Error **errp)
{
stats->account_invalid = bool_from_onoffauto(account_invalid,
stats->account_invalid);
stats->account_failed = bool_from_onoffauto(account_failed,
stats->account_failed);
if (stats_intervals) {
for (int i = 0; i < num_stats_intervals; i++) {
if (stats_intervals[i] <= 0) {
error_setg(errp, "Invalid interval length: %u", stats_intervals[i]);
return false;
}
block_acct_add_interval(stats, stats_intervals[i]);
}
g_free(stats_intervals);
}
return true;
}
void block_acct_cleanup(BlockAcctStats *stats)

View file

@ -67,11 +67,18 @@ static int block_crypto_read_func(QCryptoBlock *block,
BlockCrypto *crypto = bs->opaque;
ssize_t ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (qemu_in_coroutine()) {
GRAPH_RDLOCK_GUARD();
ret = bdrv_pread(crypto->header ? crypto->header : bs->file,
offset, buflen, buf, 0);
ret = bdrv_co_pread(crypto->header ? crypto->header : bs->file,
offset, buflen, buf, 0);
} else {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_pread(crypto->header ? crypto->header : bs->file,
offset, buflen, buf, 0);
}
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read encryption header");
return ret;
@ -90,11 +97,18 @@ static int block_crypto_write_func(QCryptoBlock *block,
BlockCrypto *crypto = bs->opaque;
ssize_t ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (qemu_in_coroutine()) {
GRAPH_RDLOCK_GUARD();
ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file,
offset, buflen, buf, 0);
ret = bdrv_co_pwrite(crypto->header ? crypto->header : bs->file,
offset, buflen, buf, 0);
} else {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file,
offset, buflen, buf, 0);
}
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write encryption header");
return ret;
@ -792,7 +806,7 @@ block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
char *buf = NULL;
int64_t size;
bool detached_hdr =
qemu_opt_get_bool(opts, "detached-header", false);
qemu_opt_get_bool_del(opts, "detached-header", false);
unsigned int cflags = 0;
int ret;
Error *local_err = NULL;

View file

@ -524,7 +524,7 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state)
#endif
#ifdef DEBUG_VERBOSE
if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) {
if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1L)) {
goto err;
}
#endif

View file

@ -46,9 +46,6 @@
/* Maximum read size for checking if data reads as zero, in bytes */
#define MAX_ZERO_CHECK_BUFFER (128 * KiB)
static void coroutine_fn GRAPH_RDLOCK
bdrv_parent_cb_resize(BlockDriverState *bs);
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
@ -2038,7 +2035,7 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
end_sector > bs->total_sectors) &&
req->type != BDRV_TRACKED_DISCARD) {
bs->total_sectors = end_sector;
bdrv_parent_cb_resize(bs);
bdrv_co_parent_cb_resize(bs);
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
}
if (req->bytes) {
@ -3570,11 +3567,11 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
bytes, read_flags, write_flags);
}
static void coroutine_fn GRAPH_RDLOCK
bdrv_parent_cb_resize(BlockDriverState *bs)
void coroutine_fn bdrv_co_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
IO_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH(c, &bs->parents, next_parent) {

View file

@ -62,7 +62,7 @@ static void hmp_drive_add_node(Monitor *mon, const char *optstr)
{
QemuOpts *opts;
QDict *qdict;
Error *local_err = NULL;
Error *err = NULL;
opts = qemu_opts_parse_noisily(&qemu_drive_opts, optstr, false);
if (!opts) {
@ -73,19 +73,19 @@ static void hmp_drive_add_node(Monitor *mon, const char *optstr)
if (!qdict_get_try_str(qdict, "node-name")) {
qobject_unref(qdict);
error_report("'node-name' needs to be specified");
error_setg(&err, "'node-name' needs to be specified");
goto out;
}
BlockDriverState *bs = bds_tree_init(qdict, &local_err);
BlockDriverState *bs = bds_tree_init(qdict, &err);
if (!bs) {
error_report_err(local_err);
goto out;
}
bdrv_set_monitor_owned(bs);
out:
qemu_opts_del(opts);
hmp_handle_error(mon, err);
}
void hmp_drive_add(Monitor *mon, const QDict *qdict)
@ -109,7 +109,6 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
mc = MACHINE_GET_CLASS(current_machine);
dinfo = drive_new(opts, mc->block_default_type, &err);
if (err) {
error_report_err(err);
qemu_opts_del(opts);
goto err;
}
@ -123,7 +122,7 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "OK\n");
break;
default:
monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type);
error_setg(&err, "Can't hot-add drive to type %d", dinfo->type);
goto err;
}
return;
@ -134,6 +133,7 @@ err:
monitor_remove_blk(blk);
blk_unref(blk);
}
hmp_handle_error(mon, err);
}
void hmp_drive_del(Monitor *mon, const QDict *qdict)
@ -141,36 +141,32 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
const char *id = qdict_get_str(qdict, "id");
BlockBackend *blk;
BlockDriverState *bs;
Error *local_err = NULL;
Error *err = NULL;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop();
bs = bdrv_find_node(id);
if (bs) {
qmp_blockdev_del(id, &local_err);
if (local_err) {
error_report_err(local_err);
}
qmp_blockdev_del(id, &err);
goto unlock;
}
blk = blk_by_name(id);
if (!blk) {
error_report("Device '%s' not found", id);
error_setg(&err, "Device '%s' not found", id);
goto unlock;
}
if (!blk_legacy_dinfo(blk)) {
error_report("Deleting device added with blockdev-add"
" is not supported");
error_setg(&err, "Deleting device added with blockdev-add"
" is not supported");
goto unlock;
}
bs = blk_bs(blk);
if (bs) {
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
error_report_err(local_err);
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &err)) {
goto unlock;
}
@ -196,6 +192,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
unlock:
bdrv_graph_rdunlock_main_loop();
hmp_handle_error(mon, err);
}
void hmp_commit(Monitor *mon, const QDict *qdict)
@ -203,6 +200,7 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
const char *device = qdict_get_str(qdict, "device");
BlockBackend *blk;
int ret;
Error *err = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
@ -214,22 +212,25 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
blk = blk_by_name(device);
if (!blk) {
error_report("Device '%s' not found", device);
return;
error_setg(&err, "Device '%s' not found", device);
goto end;
}
bs = bdrv_skip_implicit_filters(blk_bs(blk));
if (!blk_is_available(blk)) {
error_report("Device '%s' has no medium", device);
return;
error_setg(&err, "Device '%s' has no medium", device);
goto end;
}
ret = bdrv_commit(bs);
}
if (ret < 0) {
error_report("'commit' error for '%s': %s", device, strerror(-ret));
error_setg(&err, "'commit' error for '%s': %s", device, strerror(-ret));
}
end:
hmp_handle_error(mon, err);
}
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
@ -890,7 +891,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err);
if (!bs) {
error_report_err(err);
hmp_handle_error(mon, err);
return;
}

View file

@ -235,7 +235,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
* in @info, setting @errp on error.
*/
static void GRAPH_RDLOCK
bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, bool limits,
Error **errp)
{
int64_t size;
const char *backing_filename;
@ -269,6 +270,33 @@ bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
info->dirty_flag = bdi.is_dirty;
info->has_dirty_flag = true;
}
if (limits) {
info->limits = g_new(BlockLimitsInfo, 1);
*info->limits = (BlockLimitsInfo) {
.request_alignment = bs->bl.request_alignment,
.has_max_discard = bs->bl.max_pdiscard != 0,
.max_discard = bs->bl.max_pdiscard,
.has_discard_alignment = bs->bl.pdiscard_alignment != 0,
.discard_alignment = bs->bl.pdiscard_alignment,
.has_max_write_zeroes = bs->bl.max_pwrite_zeroes != 0,
.max_write_zeroes = bs->bl.max_pwrite_zeroes,
.has_write_zeroes_alignment = bs->bl.pwrite_zeroes_alignment != 0,
.write_zeroes_alignment = bs->bl.pwrite_zeroes_alignment,
.has_opt_transfer = bs->bl.opt_transfer != 0,
.opt_transfer = bs->bl.opt_transfer,
.has_max_transfer = bs->bl.max_transfer != 0,
.max_transfer = bs->bl.max_transfer,
.has_max_hw_transfer = bs->bl.max_hw_transfer != 0,
.max_hw_transfer = bs->bl.max_hw_transfer,
.max_iov = bs->bl.max_iov,
.has_max_hw_iov = bs->bl.max_hw_iov != 0,
.max_hw_iov = bs->bl.max_hw_iov,
.min_mem_alignment = bs->bl.min_mem_alignment,
.opt_mem_alignment = bs->bl.opt_mem_alignment,
};
}
info->format_specific = bdrv_get_specific_info(bs, &err);
if (err) {
error_propagate(errp, err);
@ -343,7 +371,7 @@ void bdrv_query_image_info(BlockDriverState *bs,
ImageInfo *info;
info = g_new0(ImageInfo, 1);
bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp);
bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), true, errp);
if (*errp) {
goto fail;
}
@ -389,6 +417,7 @@ fail:
*/
void bdrv_query_block_graph_info(BlockDriverState *bs,
BlockGraphInfo **p_info,
bool limits,
Error **errp)
{
ERRP_GUARD();
@ -397,7 +426,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
BdrvChild *c;
info = g_new0(BlockGraphInfo, 1);
bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp);
bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), limits, errp);
if (*errp) {
goto fail;
}
@ -411,7 +440,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
QAPI_LIST_APPEND(children_list_tail, c_info);
c_info->name = g_strdup(c->name);
bdrv_query_block_graph_info(c->bs, &c_info->info, errp);
bdrv_query_block_graph_info(c->bs, &c_info->info, limits, errp);
if (*errp) {
goto fail;
}
@ -908,6 +937,29 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
visit_free(v);
}
/**
* Dumps the given BlockLimitsInfo object in a human-readable form,
* prepending an optional prefix if the dump is not empty.
*/
static void bdrv_image_info_limits_dump(BlockLimitsInfo *limits,
const char *prefix,
int indentation)
{
QObject *obj;
Visitor *v = qobject_output_visitor_new(&obj);
visit_type_BlockLimitsInfo(v, NULL, &limits, &error_abort);
visit_complete(v, &obj);
if (!qobject_is_empty_dump(obj)) {
if (prefix) {
qemu_printf("%*s%s", indentation * 4, "", prefix);
}
dump_qobject(indentation + 1, obj);
}
qobject_unref(obj);
visit_free(v);
}
/**
* Print the given @info object in human-readable form. Every field is indented
* using the given @indentation (four spaces per indentation level).
@ -983,6 +1035,12 @@ void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol)
}
}
if (info->limits) {
bdrv_image_info_limits_dump(info->limits,
"Block limits:\n",
indentation);
}
if (info->has_snapshots) {
SnapshotInfoList *elem;

View file

@ -617,7 +617,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
bs->detect_zeroes = detect_zeroes;
block_acct_setup(blk_get_stats(blk), account_invalid, account_failed);
block_acct_setup(blk_get_stats(blk), account_invalid, account_failed,
NULL, 0, NULL);
if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
blk_unref(blk);

View file

@ -503,7 +503,7 @@ Command description:
The size syntax is similar to :manpage:`dd(1)`'s size syntax.
.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-t CACHE] [-U] FILENAME
Give information about the disk image *FILENAME*. Use it in
particular to know the size reserved on disk which can be different
@ -571,6 +571,10 @@ Command description:
``ImageInfoSpecific*`` QAPI object (e.g. ``ImageInfoSpecificQCow2``
for qcow2 images).
*Block limits*
The block limits for I/O that QEMU detected for the image.
This information is only shown if the ``--limits`` option was specified.
.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--start-offset=OFFSET] [--max-length=LEN] [--output=OFMT] [-U] FILENAME
Dump the metadata of image *FILENAME* and its backing file chain.

View file

@ -249,8 +249,11 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
blk_set_enable_write_cache(blk, wce);
blk_set_on_error(blk, rerror, werror);
block_acct_setup(blk_get_stats(blk), conf->account_invalid,
conf->account_failed);
if (!block_acct_setup(blk_get_stats(blk), conf->account_invalid,
conf->account_failed, conf->stats_intervals,
conf->num_stats_intervals, errp)) {
return false;
}
return true;
}

View file

@ -101,8 +101,9 @@ typedef struct BlockAcctCookie {
} BlockAcctCookie;
void block_acct_init(BlockAcctStats *stats);
void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
enum OnOffAuto account_failed);
bool block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
enum OnOffAuto account_failed, uint32_t *stats_intervals,
uint32_t num_stats_intervals, Error **errp);
void block_acct_cleanup(BlockAcctStats *stats);
void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length);
BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats,

View file

@ -817,10 +817,10 @@ typedef struct BlockLimits {
int64_t max_pdiscard;
/*
* Optimal alignment for discard requests in bytes. A power of 2
* is best but not mandatory. Must be a multiple of
* bl.request_alignment, and must be less than max_pdiscard if
* that is set. May be 0 if bl.request_alignment is good enough
* Optimal alignment for discard requests in bytes. Note that this doesn't
* have to be a power of two. Must be a multiple of bl.request_alignment,
* and must be less than max_pdiscard if that is set. May be 0 if
* bl.request_alignment is good enough.
*/
uint32_t pdiscard_alignment;
@ -831,11 +831,10 @@ typedef struct BlockLimits {
int64_t max_pwrite_zeroes;
/*
* Optimal alignment for write zeroes requests in bytes. A power
* of 2 is best but not mandatory. Must be a multiple of
* bl.request_alignment, and must be less than max_pwrite_zeroes
* if that is set. May be 0 if bl.request_alignment is good
* enough
* Optimal alignment for write zeroes requests in bytes. Note that this
* doesn't have to be a power of two. Must be a multiple of
* bl.request_alignment, and must be less than max_pwrite_zeroes if that is
* set. May be 0 if bl.request_alignment is good enough.
*/
uint32_t pwrite_zeroes_alignment;
@ -863,18 +862,23 @@ typedef struct BlockLimits {
uint64_t max_hw_transfer;
/*
* Maximal number of scatter/gather elements allowed by the hardware.
* Maximum number of scatter/gather elements allowed by the hardware.
* Applies whenever transfers to the device bypass the kernel I/O
* scheduler, for example with SG_IO. If larger than max_iov
* or if zero, blk_get_max_hw_iov will fall back to max_iov.
*/
int max_hw_iov;
/* memory alignment, in bytes so that no bounce buffer is needed */
/*
* Minimal required memory alignment in bytes for zero-copy I/O to succeed.
* For unaligned requests, a bounce buffer will be used.
*/
size_t min_mem_alignment;
/* memory alignment, in bytes, for bounce buffer */
/*
* Optimal memory alignment in bytes. This is the alignment used for any
* buffer allocations QEMU performs internally.
*/
size_t opt_mem_alignment;
/* maximum number of iovec elements */
@ -1020,7 +1024,10 @@ struct BdrvChildClass {
* the I/O API.
*/
void (*resize)(BdrvChild *child);
/*
* Notifies the parent that the child was resized.
*/
void GRAPH_RDLOCK_PTR (*resize)(BdrvChild *child);
/*
* Returns a name that is supposedly more useful for human users than the

View file

@ -191,4 +191,10 @@ void bdrv_bsc_invalidate_range(BlockDriverState *bs,
*/
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
/*
* Notify all parents that the size of the child changed.
*/
void coroutine_fn GRAPH_RDLOCK
bdrv_co_parent_cb_resize(BlockDriverState *bs);
#endif /* BLOCK_INT_IO_H */

View file

@ -42,7 +42,7 @@ bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat,
bool skip_implicit_filters, Error **errp);
void GRAPH_RDLOCK
bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info,
Error **errp);
bool limits, Error **errp);
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn);
void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,

View file

@ -34,6 +34,8 @@ typedef struct BlockConf {
OnOffAuto account_invalid, account_failed;
BlockdevOnError rerror;
BlockdevOnError werror;
uint32_t num_stats_intervals;
uint32_t *stats_intervals;
} BlockConf;
static inline unsigned int get_physical_block_exp(BlockConf *conf)
@ -66,7 +68,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
DEFINE_PROP_ON_OFF_AUTO("account-invalid", _state, \
_conf.account_invalid, ON_OFF_AUTO_AUTO), \
DEFINE_PROP_ON_OFF_AUTO("account-failed", _state, \
_conf.account_failed, ON_OFF_AUTO_AUTO)
_conf.account_failed, ON_OFF_AUTO_AUTO), \
DEFINE_PROP_ARRAY("stats-intervals", _state, \
_conf.num_stats_intervals, _conf.stats_intervals, \
qdev_prop_uint32, uint32_t)
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \

View file

@ -275,6 +275,69 @@
'file': 'ImageInfoSpecificFileWrapper'
} }
##
# @BlockLimitsInfo:
#
# @request-alignment: Alignment requirement, in bytes, for
# offset/length of I/O requests.
#
# @max-discard: Maximum number of bytes that can be discarded at once.
# If not present, there is no specific maximum.
#
# @discard-alignment: Optimal alignment for discard requests in bytes.
# Note that this doesn't have to be a power of two. If not
# present, discards don't have a alignment requirement different
# from @request-alignment.
#
# @max-write-zeroes: Maximum number of bytes that can be zeroed out at
# once. If not present, there is no specific maximum.
#
# @write-zeroes-alignment: Optimal alignment for write zeroes requests
# in bytes. Note that this doesn't have to be a power of two. If
# not present, write_zeroes doesn't have a alignment requirement
# different from @request-alignment.
#
# @opt-transfer: Optimal transfer length in bytes. If not present,
# there is no preferred size.
#
# @max-transfer: Maximal transfer length in bytes. If not present,
# there is no specific maximum.
#
# @max-hw-transfer: Maximal hardware transfer length in bytes.
# Applies whenever transfers to the device bypass the kernel I/O
# scheduler, for example with SG_IO. If not present, there is no
# specific maximum.
#
# @max-iov: Maximum number of scatter/gather elements
#
# @max-hw-iov: Maximum number of scatter/gather elements allowed by
# the hardware. Applies whenever transfers to the device bypass
# the kernel I/O scheduler, for example with SG_IO. If not
# present, the hardware limits is unknown and @max-iov is always
# used.
#
# @min-mem-alignment: Minimal required memory alignment in bytes for
# zero-copy I/O to succeed. For unaligned requests, a bounce
# buffer will be used.
#
# @opt-mem-alignment: Optimal memory alignment in bytes. This is the
# alignment used for any buffer allocations QEMU performs
# internally.
##
{ 'struct': 'BlockLimitsInfo',
'data': { 'request-alignment': 'uint32',
'*max-discard': 'uint64',
'*discard-alignment': 'uint32',
'*max-write-zeroes': 'uint64',
'*write-zeroes-alignment': 'uint32',
'*opt-transfer': 'uint32',
'*max-transfer': 'uint32',
'*max-hw-transfer': 'uint32',
'max-iov': 'int',
'*max-hw-iov': 'int',
'min-mem-alignment': 'size',
'opt-mem-alignment': 'size' } }
##
# @BlockNodeInfo:
#
@ -304,6 +367,8 @@
#
# @snapshots: list of VM snapshots
#
# @limits: block limits that are used for I/O on the node (Since 10.2)
#
# @format-specific: structure supplying additional format-specific
# information (since 1.7)
#
@ -315,6 +380,7 @@
'*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool',
'*backing-filename': 'str', '*full-backing-filename': 'str',
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
'*limits': 'BlockLimitsInfo',
'*format-specific': 'ImageInfoSpecific' } }
##

View file

@ -66,9 +66,9 @@ SRST
ERST
DEF("info", img_info,
"info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [-U] filename")
"info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [--limits] [-t CACHE] [-U] filename")
SRST
.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-t CACHE] [-U] FILENAME
ERST
DEF("map", img_map,

View file

@ -86,6 +86,7 @@ enum {
OPTION_BITMAPS = 275,
OPTION_FORCE = 276,
OPTION_SKIP_BROKEN = 277,
OPTION_LIMITS = 278,
};
typedef enum OutputFormat {
@ -3002,12 +3003,23 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b)
static BlockGraphInfoList *collect_image_info_list(bool image_opts,
const char *filename,
const char *fmt,
bool chain, bool force_share)
const char *cache,
bool chain, bool limits,
bool force_share)
{
BlockGraphInfoList *head = NULL;
BlockGraphInfoList **tail = &head;
GHashTable *filenames;
Error *err = NULL;
int cache_flags = 0;
bool writethrough = false;
int ret;
ret = bdrv_parse_cache_mode(cache, &cache_flags, &writethrough);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
return NULL;
}
filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
@ -3024,8 +3036,8 @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
g_hash_table_insert(filenames, (gpointer)filename, NULL);
blk = img_open(image_opts, filename, fmt,
BDRV_O_NO_BACKING | BDRV_O_NO_IO, false, false,
force_share);
BDRV_O_NO_BACKING | BDRV_O_NO_IO | cache_flags,
writethrough, false, force_share);
if (!blk) {
goto err;
}
@ -3039,7 +3051,7 @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
* the chain manually here.
*/
bdrv_graph_rdlock_main_loop();
bdrv_query_block_graph_info(bs, &info, &err);
bdrv_query_block_graph_info(bs, &info, limits, &err);
bdrv_graph_rdunlock_main_loop();
if (err) {
@ -3085,9 +3097,11 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
OutputFormat output_format = OFORMAT_HUMAN;
bool chain = false;
const char *filename, *fmt;
const char *cache = BDRV_DEFAULT_CACHE;
BlockGraphInfoList *list;
bool image_opts = false;
bool force_share = false;
bool limits = false;
fmt = NULL;
for(;;) {
@ -3096,12 +3110,14 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
{"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
{"cache", required_argument, 0, 't'},
{"force-share", no_argument, 0, 'U'},
{"limits", no_argument, 0, OPTION_LIMITS},
{"output", required_argument, 0, OPTION_OUTPUT},
{"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "hf:U", long_options, NULL);
c = getopt_long(argc, argv, "hf:t:U", long_options, NULL);
if (c == -1) {
break;
}
@ -3117,8 +3133,12 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
" (incompatible with -f|--format)\n"
" --backing-chain\n"
" display information about the backing chain for copy-on-write overlays\n"
" -t, --cache CACHE\n"
" cache mode for FILE (default: " BDRV_DEFAULT_CACHE ")\n"
" -U, --force-share\n"
" open image in shared mode for concurrent access\n"
" --limits\n"
" show detected block limits (may depend on options, e.g. cache mode)\n"
" --output human|json\n"
" specify output format (default: human)\n"
" --object OBJDEF\n"
@ -3137,9 +3157,15 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
case OPTION_BACKING_CHAIN:
chain = true;
break;
case 't':
cache = optarg;
break;
case 'U':
force_share = true;
break;
case OPTION_LIMITS:
limits = true;
break;
case OPTION_OUTPUT:
output_format = parse_output_format(argv[0], optarg);
break;
@ -3155,8 +3181,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
}
filename = argv[optind++];
list = collect_image_info_list(image_opts, filename, fmt, chain,
force_share);
list = collect_image_info_list(image_opts, filename, fmt, cache, chain,
limits, force_share);
if (!list) {
return 1;
}

View file

@ -23,6 +23,6 @@ Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864
{'execute': 'quit'}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done

View file

@ -5,7 +5,7 @@ QMP_VERSION
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done

View file

@ -30,6 +30,7 @@ Testing:
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
@ -59,6 +60,7 @@ Testing: -fda TEST_DIR/t.qcow2
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -95,6 +97,7 @@ Testing: -fdb TEST_DIR/t.qcow2
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -109,6 +112,7 @@ Testing: -fdb TEST_DIR/t.qcow2
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -149,6 +153,7 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -163,6 +168,7 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -204,6 +210,7 @@ Testing: -fdb
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
dev: floppy, id ""
unit = 0 (0x0)
@ -218,6 +225,7 @@ Testing: -fdb
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
@ -247,6 +255,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -283,6 +292,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -297,6 +307,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -337,6 +348,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -351,6 +363,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -395,6 +408,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -431,6 +445,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -467,6 +482,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -481,6 +497,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -531,6 +548,7 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -545,6 +563,7 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -586,6 +605,7 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -600,6 +620,7 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -641,6 +662,7 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 1 (0x1)
@ -655,6 +677,7 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -696,6 +719,7 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 1 (0x1)
@ -710,6 +734,7 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -760,6 +785,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -774,6 +800,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -815,6 +842,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
dev: floppy, id ""
unit = 0 (0x0)
@ -829,6 +857,7 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/unattached/device[N]
@ -876,6 +905,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global floppy.drive=none0 -device
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -942,6 +972,7 @@ Testing: -device floppy
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
Testing: -device floppy,drive-type=120
@ -968,6 +999,7 @@ Testing: -device floppy,drive-type=120
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "120"
Testing: -device floppy,drive-type=144
@ -994,6 +1026,7 @@ Testing: -device floppy,drive-type=144
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
Testing: -device floppy,drive-type=288
@ -1020,6 +1053,7 @@ Testing: -device floppy,drive-type=288
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
@ -1049,6 +1083,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "120"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -1085,6 +1120,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "288"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -1124,6 +1160,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]
@ -1160,6 +1197,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica
share-rw = false
account-invalid = "auto"
account-failed = "auto"
stats-intervals = <null>
drive-type = "144"
none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Attached to: /machine/peripheral-anon/device[N]

View file

@ -45,8 +45,9 @@ do_run_qemu()
run_qemu()
{
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
| _filter_qemu_io | _filter_generated_node_ids
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
| _filter_qemu_io | _filter_generated_node_ids \
| _filter_img_info
}
test_throttle=$($QEMU_IMG --help|grep throttle)

View file

@ -41,12 +41,6 @@ Testing:
},
"iops_wr": 0,
"ro": false,
"children": [
{
"node-name": "disk0",
"child": "file"
}
],
"node-name": "throttle0",
"backing_file_depth": 1,
"drv": "throttle",
@ -75,8 +69,6 @@ Testing:
},
"iops_wr": 0,
"ro": false,
"children": [
],
"node-name": "disk0",
"backing_file_depth": 0,
"drv": "null-co",

View file

@ -8,7 +8,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0
Error: no block device can store vmstate for snapshot
(qemu) info snapshots
no block device can store vmstate for snapshot
Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: no block device can store vmstate for snapshot
(qemu) quit
@ -22,7 +22,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0
Error: Device 'none0' is writable but does not support snapshots
(qemu) info snapshots
no block device can store vmstate for snapshot
Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: Device 'none0' is writable but does not support snapshots
(qemu) quit
@ -58,7 +58,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0
Error: Device 'virtio0' is writable but does not support snapshots
(qemu) info snapshots
no block device can store vmstate for snapshot
Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: Device 'virtio0' is writable but does not support snapshots
(qemu) quit
@ -83,7 +83,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0
Error: Device 'file' is writable but does not support snapshots
(qemu) info snapshots
no block device can store vmstate for snapshot
Error: no block device can store vmstate for snapshot
(qemu) loadvm snap0
Error: Device 'file' is writable but does not support snapshots
(qemu) quit

View file

@ -229,6 +229,7 @@ _filter_img_info()
discard=0
regex_json_spec_start='^ *"format-specific": \{'
regex_json_child_start='^ *"children": \['
regex_json_limit_start='^ *"limits": \{'
gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
@ -261,7 +262,7 @@ _filter_img_info()
discard=1
elif [[ $line =~ "Child node '/" ]]; then
discard=1
elif [[ $line =~ $regex_json_spec_start ]]; then
elif [[ $line =~ $regex_json_spec_start || $line =~ $regex_json_limit_start ]]; then
discard=2
regex_json_end="^${line%%[^ ]*}\\},? *$"
elif [[ $line =~ $regex_json_child_start ]]; then

View file

@ -28,9 +28,9 @@ stat: cannot statx 'fuse-export': Permission denied
cat: fuse-export: Permission denied
stat: cannot statx 'fuse-export': Permission denied
{'execute': 'quit'}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
{"return": {}}
--- allow-other=on ---
{'execute': 'qmp_capabilities'}
@ -55,9 +55,9 @@ Permissions seen by nobody: 444
cat: fuse-export: Permission denied
Permissions seen by nobody: 440
{'execute': 'quit'}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
{"return": {}}
--- allow-other=auto ---
{'execute': 'qmp_capabilities'}
@ -82,7 +82,7 @@ Permissions seen by nobody: 444
cat: fuse-export: Permission denied
Permissions seen by nobody: 440
{'execute': 'quit'}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
{"return": {}}
*** done

View file

@ -24,6 +24,7 @@ from iotests import QemuIoInteractive
from iotests import filter_qemu_io, filter_qtest, filter_qmp_testfiles
iotests.script_initialize(supported_fmts=['generic'],
unsupported_fmts=['luks'],
supported_protocols=['file'],
supported_platforms=['linux'])

View file

@ -0,0 +1,73 @@
#!/usr/bin/env python3
# group: rw quick
#
# Test what happens when a node below filter nodes is resized.
#
# Copyright (C) Proxmox Server Solutions GmbH
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import iotests
from iotests import imgfmt, qemu_img_create, QMPTestCase
image_size = 1 * 1024 * 1024
image = os.path.join(iotests.test_dir, 'test.img')
class TestResizeBelowFilter(QMPTestCase):
def setUp(self) -> None:
qemu_img_create('-f', imgfmt, image, str(image_size))
self.vm = iotests.VM()
self.vm.add_blockdev(self.vm.qmp_to_opts({
'driver': imgfmt,
'node-name': 'node0',
'file': {
'driver': 'file',
'filename': image,
}
}))
self.vm.add_blockdev(self.vm.qmp_to_opts({
'driver': 'compress',
'node-name': 'comp0',
'file': 'node0',
}))
self.vm.add_object('throttle-group,id=thrgr0')
self.vm.add_blockdev(self.vm.qmp_to_opts({
'driver': 'throttle',
'node-name': 'thr0',
'throttle-group': 'thrgr0',
'file': 'comp0',
}))
self.vm.add_object('throttle-group,id=thrgr1')
self.vm.add_blockdev(self.vm.qmp_to_opts({
'driver': 'throttle',
'node-name': 'thr1',
'throttle-group': 'thrgr1',
'file': 'node0',
}))
self.vm.launch()
def tearDown(self) -> None:
self.vm.shutdown()
os.remove(image)
def assert_size(self, size: int) -> None:
nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
self.assertEqual(len(nodes), 5)
for node in nodes:
if node['drv'] == 'file':
continue
self.assertEqual(node['image']['virtual-size'], size)
def test_resize_below_filter(self) -> None:
self.assert_size(image_size)
self.vm.qmp('block_resize', node_name='thr0', size=2*image_size)
self.assert_size(2*image_size)
self.vm.qmp('block_resize', node_name='comp0', size=3*image_size)
self.assert_size(3*image_size)
self.vm.qmp('block_resize', node_name='node0', size=4*image_size)
self.assert_size(4*image_size)
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'], supported_protocols=['file'])

View file

@ -0,0 +1,5 @@
.
----------------------------------------------------------------------
Ran 1 tests
OK

View file

@ -0,0 +1,53 @@
#!/usr/bin/env python3
# group: rw quick
#
# Test what happens when a 'file' node below a 'raw' node is resized.
#
# Copyright (C) Proxmox Server Solutions GmbH
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import iotests
from iotests import imgfmt, qemu_img_create, QMPTestCase
image_size = 1 * 1024 * 1024
image = os.path.join(iotests.test_dir, 'test.img')
class TestResizeBelowRaw(QMPTestCase):
def setUp(self) -> None:
qemu_img_create('-f', imgfmt, image, str(image_size))
self.vm = iotests.VM()
self.vm.add_blockdev(self.vm.qmp_to_opts({
'driver': imgfmt,
'node-name': 'node0',
'file': {
'driver': 'file',
'filename': image,
'node-name': 'file0',
}
}))
self.vm.launch()
def tearDown(self) -> None:
self.vm.shutdown()
os.remove(image)
def assert_size(self, size: int) -> None:
nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
self.assertEqual(len(nodes), 2)
for node in nodes:
if node['drv'] == 'file':
continue
self.assertEqual(node['image']['virtual-size'], size)
def test_resize_below_raw(self) -> None:
self.assert_size(image_size)
self.vm.qmp('block_resize', node_name='file0', size=2*image_size)
self.assert_size(2*image_size)
self.vm.qmp('block_resize', node_name='node0', size=3*image_size)
self.assert_size(3*image_size)
if __name__ == '__main__':
iotests.main(supported_fmts=['raw'], supported_protocols=['file'])

View file

@ -0,0 +1,5 @@
.
----------------------------------------------------------------------
Ran 1 tests
OK