+ 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,
diff --git a/block/accounting.c b/block/accounting.c
index a74551d41f2..debf1924455 100644
--- a/block/accounting.c
+++ b/block/accounting.c
@@ -27,8 +27,10 @@
#include "block/accounting.h"
#include "block/block_int.h"
#include "qemu/timer.h"
+#include "system/block-backend.h"
#include "system/qtest.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-block.h"
static QEMUClockType clock_type = QEMU_CLOCK_REALTIME;
static const int qtest_latency_ns = NANOSECONDS_PER_SECOND / 1000;
@@ -62,9 +64,35 @@ static bool bool_from_onoffauto(OnOffAuto val, bool def)
}
}
+/**
+ * Convert a BlockAcctType into its QAPI equivalent IoAccountingOperation.
+ *
+ * Must only be called for valid BlockAcctType values, i.e. specifically not
for
+ * `BLOCK_ACCT_NONE`.
+ */
+static IoAccountingOperation block_acct_qapi_type(enum BlockAcctType type)
+{
+ switch (type) {
+ case BLOCK_ACCT_READ:
+ return IO_ACCOUNTING_OPERATION_READ;
+ case BLOCK_ACCT_WRITE:
+ return IO_ACCOUNTING_OPERATION_WRITE;
+ case BLOCK_ACCT_FLUSH:
+ return IO_ACCOUNTING_OPERATION_FLUSH;
+ case BLOCK_ACCT_ZONE_APPEND:
+ return IO_ACCOUNTING_OPERATION_ZONE_APPEND;
+ case BLOCK_ACCT_UNMAP:
+ return IO_ACCOUNTING_OPERATION_UNMAP;
+ case BLOCK_ACCT_NONE:
+ default:
+ g_assert_not_reached();
+ }
+}
+
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)
+ uint32_t num_stats_intervals, int64_t alert_ns,
+ Error **errp)
{
stats->account_invalid = bool_from_onoffauto(account_invalid,
stats->account_invalid);
@@ -79,6 +107,7 @@ bool block_acct_setup(BlockAcctStats *stats, enum OnOffAuto
account_invalid,
block_acct_add_interval(stats, stats_intervals[i]);
}
}
+ stats->delay_threshold_ns = alert_ns;
return true;
}
@@ -252,6 +281,17 @@ static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie,
return;
}
+ if (stats->delay_threshold_ns && latency_ns > stats->delay_threshold_ns) {
+ g_autofree char *dev_path = blk_get_attached_dev_path(stats->blk);
+ double latency = latency_ns / (double)NANOSECONDS_PER_SECOND;
+
+ qapi_event_send_block_io_delay(dev_path,
+ block_acct_qapi_type(cookie->type),
+ latency,
+ cookie->offset >= 0, cookie->offset,
+ cookie->bytes);
+ }
+
WITH_QEMU_LOCK_GUARD(&stats->lock) {
if (failed) {
stats->failed_ops[cookie->type]++;
diff --git a/blockdev.c b/blockdev.c
index 6e86c6262f9..195bac8af01 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -618,7 +618,7 @@ 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,
- NULL, 0, NULL);
+ NULL, 0, 0, NULL);
if (!parse_stats_intervals(blk_get_stats(blk), interval_list, errp)) {
blk_unref(blk);
diff --git a/hw/block/block.c b/hw/block/block.c
index f187fa025d0..19301c6f995 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -251,7 +251,7 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool
readonly,
if (!block_acct_setup(blk_get_stats(blk), conf->account_invalid,
conf->account_failed, conf->stats_intervals,
- conf->num_stats_intervals, errp)) {
+ conf->num_stats_intervals, 0, errp)) {
return false;
}
return true;
--
2.55.0