mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+1
-1
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
+15
-2
@@ -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)
|
||||
|
||||
+23
-9
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+3
-6
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+62
-4
@@ -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;
|
||||
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
+5
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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' } }
|
||||
|
||||
##
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
+33
-7
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user