This patch allows the stats-intervals.* flag to be used with -blockdev. Stats collection is initialized for virtio-blk devices at their time of creation. However, it is limited to just virtio-blk devices for now.
Signed-off-by: Chandan <[email protected]> --- block.c | 50 ++++++++++++++++++++++++++++++++ hw/block/virtio-blk.c | 6 ++++ include/block/block_int-common.h | 4 +++ qapi/block-core.json | 6 +++- 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 8848e9a7ed..e455d04e97 100644 --- a/block.c +++ b/block.c @@ -38,7 +38,9 @@ #include "qapi/error.h" #include "qobject/qdict.h" #include "qobject/qjson.h" +#include "qobject/qlist.h" #include "qobject/qnull.h" +#include "qobject/qnum.h" #include "qobject/qstring.h" #include "qapi/qobject-output-visitor.h" #include "qapi/qapi-visit-block-core.h" @@ -3956,6 +3958,35 @@ out: return bs_snapshot; } +static bool bdrv_parse_stats_intervals(BlockDriverState *bs, QList *intervals, + Error **errp) +{ + unsigned i = 0; + const QListEntry *entry; + bs->num_stats_intervals = qlist_size(intervals); + + if (bs->num_stats_intervals > 0) { + bs->stats_intervals = g_new(uint64_t, bs->num_stats_intervals); + } + + for (entry = qlist_first(intervals); entry; entry = qlist_next(entry)) { + if (qobject_type(entry->value) == QTYPE_QNUM) { + uint64_t length = qnum_get_int(qobject_to(QNum, entry->value)); + + if (length > 0 && length <= UINT_MAX) { + bs->stats_intervals[i++] = length; + } else { + error_setg(errp, "Invalid interval length: %" PRId64, length); + return false; + } + } else { + error_setg(errp, "The specification of stats-intervals is invalid"); + return false; + } + } + return true; +} + /* * Opens a disk image (raw, qcow2, vmdk, ...) * @@ -3987,6 +4018,8 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options, Error *local_err = NULL; QDict *snapshot_options = NULL; int snapshot_flags = 0; + QDict *interval_dict = NULL; + QList *interval_list = NULL; assert(!child_class || !flags); assert(!child_class == !parent); @@ -4205,6 +4238,19 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options, g_free(child_key_dot); } + qdict_extract_subqdict(options, &interval_dict, "stats-intervals."); + qdict_array_split(interval_dict, &interval_list); + + if (qdict_size(interval_dict) != 0) { + error_setg(errp, "Invalid option stats-intervals.%s", + qdict_first(interval_dict)->key); + goto close_and_fail; + } + + if (!bdrv_parse_stats_intervals(bs, interval_list, errp)) { + goto close_and_fail; + } + /* Check if any unknown options were used */ if (qdict_size(options) != 0) { const QDictEntry *entry = qdict_first(options); @@ -4261,6 +4307,8 @@ close_and_fail: bdrv_unref(bs); qobject_unref(snapshot_options); qobject_unref(options); + qobject_unref(interval_dict); + qobject_unref(interval_list); error_propagate(errp, local_err); return NULL; } @@ -5190,6 +5238,8 @@ static void GRAPH_UNLOCKED bdrv_close(BlockDriverState *bs) bs->full_open_options = NULL; g_free(bs->block_status_cache); bs->block_status_cache = NULL; + g_free(bs->stats_intervals); + bs->stats_intervals = NULL; bdrv_release_named_dirty_bitmaps(bs); assert(QLIST_EMPTY(&bs->dirty_bitmaps)); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 9bab2716c1..b730c67940 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1814,6 +1814,12 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) conf->conf.lcyls, conf->conf.lheads, conf->conf.lsecs); + + if (bs->stats_intervals) { + for (i = 0; i < bs->num_stats_intervals; i++) { + block_acct_add_interval(blk_get_stats(s->blk), bs->stats_intervals[i]); + } + } } static void virtio_blk_device_unrealize(DeviceState *dev) diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 034c0634c8..1b4b7c636d 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -1277,6 +1277,10 @@ struct BlockDriverState { /* array of write pointers' location of each zone in the zoned device. */ BlockZoneWps *wps; + + /* Array of intervals for collecting IO stats */ + uint64_t *stats_intervals; + unsigned int num_stats_intervals; }; struct BlockBackendRootState { diff --git a/qapi/block-core.json b/qapi/block-core.json index dc6eb4ae23..dbb53296b1 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4771,6 +4771,9 @@ # @force-share: force share all permission on added nodes. Requires # read-only=true. (Since 2.10) # +# @stats-intervals: #optional list of intervals for collecting I/O +# statistics, in seconds (default: none) +# # Since: 2.9 ## { 'union': 'BlockdevOptions', @@ -4782,7 +4785,8 @@ '*read-only': 'bool', '*auto-read-only': 'bool', '*force-share': 'bool', - '*detect-zeroes': 'BlockdevDetectZeroesOptions' }, + '*detect-zeroes': 'BlockdevDetectZeroesOptions', + '*stats-intervals': ['int'] }, 'discriminator': 'driver', 'data': { 'blkdebug': 'BlockdevOptionsBlkdebug', -- 2.51.0
