diff options
-rw-r--r-- | block/accounting.c | 23 | ||||
-rw-r--r-- | block/qapi.c | 10 | ||||
-rw-r--r-- | include/block/accounting.h | 4 | ||||
-rw-r--r-- | qapi/block-core.json | 23 | ||||
-rw-r--r-- | qmp-commands.hx | 12 |
5 files changed, 71 insertions, 1 deletions
diff --git a/block/accounting.c b/block/accounting.c index d427fa8fb8..49a9444377 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -51,6 +51,29 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) stats->last_access_time_ns = time_ns; } +void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie) +{ + int64_t time_ns = qemu_clock_get_ns(clock_type); + + assert(cookie->type < BLOCK_MAX_IOTYPE); + + stats->failed_ops[cookie->type]++; + stats->total_time_ns[cookie->type] += time_ns - cookie->start_time_ns; + stats->last_access_time_ns = time_ns; +} + +void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type) +{ + assert(type < BLOCK_MAX_IOTYPE); + + /* block_acct_done() and block_acct_failed() update + * total_time_ns[], but this one does not. The reason is that + * invalid requests are accounted during their submission, + * therefore there's no actual I/O involved. */ + + stats->invalid_ops[type]++; + stats->last_access_time_ns = qemu_clock_get_ns(clock_type); +} void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, int num_requests) diff --git a/block/qapi.c b/block/qapi.c index 9799656761..d1a6bdc1d2 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -351,6 +351,16 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs, s->stats->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE]; s->stats->rd_operations = stats->nr_ops[BLOCK_ACCT_READ]; s->stats->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE]; + + s->stats->failed_rd_operations = stats->failed_ops[BLOCK_ACCT_READ]; + s->stats->failed_wr_operations = stats->failed_ops[BLOCK_ACCT_WRITE]; + s->stats->failed_flush_operations = stats->failed_ops[BLOCK_ACCT_FLUSH]; + + s->stats->invalid_rd_operations = stats->invalid_ops[BLOCK_ACCT_READ]; + s->stats->invalid_wr_operations = stats->invalid_ops[BLOCK_ACCT_WRITE]; + s->stats->invalid_flush_operations = + stats->invalid_ops[BLOCK_ACCT_FLUSH]; + s->stats->rd_merged = stats->merged[BLOCK_ACCT_READ]; s->stats->wr_merged = stats->merged[BLOCK_ACCT_WRITE]; s->stats->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH]; diff --git a/include/block/accounting.h b/include/block/accounting.h index 4b2b999bd0..b50e3cc8d2 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -38,6 +38,8 @@ enum BlockAcctType { typedef struct BlockAcctStats { uint64_t nr_bytes[BLOCK_MAX_IOTYPE]; uint64_t nr_ops[BLOCK_MAX_IOTYPE]; + uint64_t invalid_ops[BLOCK_MAX_IOTYPE]; + uint64_t failed_ops[BLOCK_MAX_IOTYPE]; uint64_t total_time_ns[BLOCK_MAX_IOTYPE]; uint64_t merged[BLOCK_MAX_IOTYPE]; int64_t last_access_time_ns; @@ -52,6 +54,8 @@ typedef struct BlockAcctCookie { void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, int64_t bytes, enum BlockAcctType type); void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie); +void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie); +void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type); void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, int num_requests); int64_t block_acct_idle_time_ns(BlockAcctStats *stats); diff --git a/qapi/block-core.json b/qapi/block-core.json index 597281821b..009b7c88f9 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -452,6 +452,24 @@ # nanoseconds. If the field is absent it means that # there haven't been any operations yet (Since 2.5). # +# @failed_rd_operations: The number of failed read operations +# performed by the device (Since 2.5) +# +# @failed_wr_operations: The number of failed write operations +# performed by the device (Since 2.5) +# +# @failed_flush_operations: The number of failed flush operations +# performed by the device (Since 2.5) +# +# @invalid_rd_operations: The number of invalid read operations +# performed by the device (Since 2.5) +# +# @invalid_wr_operations: The number of invalid write operations +# performed by the device (Since 2.5) +# +# @invalid_flush_operations: The number of invalid flush operations +# performed by the device (Since 2.5) +# # Since: 0.14.0 ## { 'struct': 'BlockDeviceStats', @@ -459,7 +477,10 @@ 'wr_operations': 'int', 'flush_operations': 'int', 'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int', 'rd_total_time_ns': 'int', 'wr_highest_offset': 'int', - 'rd_merged': 'int', 'wr_merged': 'int', '*idle_time_ns': 'int' } } + 'rd_merged': 'int', 'wr_merged': 'int', '*idle_time_ns': 'int', + 'failed_rd_operations': 'int', 'failed_wr_operations': 'int', + 'failed_flush_operations': 'int', 'invalid_rd_operations': 'int', + 'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int' } } ## # @BlockStats: diff --git a/qmp-commands.hx b/qmp-commands.hx index 5c4c16fe9b..b031df6942 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2587,6 +2587,18 @@ Each json-object contain the following: nanoseconds. If the field is absent it means that there haven't been any operations yet (json-int, optional) + - "failed_rd_operations": number of failed read operations + (json-int) + - "failed_wr_operations": number of failed write operations + (json-int) + - "failed_flush_operations": number of failed flush operations + (json-int) + - "invalid_rd_operations": number of invalid read operations + (json-int) + - "invalid_wr_operations": number of invalid write operations + (json-int) + - "invalid_flush_operations": number of invalid flush operations + (json-int) - "parent": Contains recursively the statistics of the underlying protocol (e.g. the host file for a qcow2 image). If there is no underlying protocol, this field is omitted |