return info;
}
-int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
- const char *dev_name,
- long long *rd_req,
- long long *rd_bytes,
- long long *rd_total_times,
- long long *wr_req,
- long long *wr_bytes,
- long long *wr_total_times,
- long long *flush_req,
- long long *flush_total_times)
-{
- int ret;
- VIR_DEBUG("mon=%p dev=%s", mon, dev_name);
-
- if (!mon) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("monitor must not be NULL"));
- return -1;
- }
-
- if (mon->json)
- ret = qemuMonitorJSONGetBlockStatsInfo(mon, dev_name,
- rd_req, rd_bytes,
- rd_total_times,
- wr_req, wr_bytes,
- wr_total_times,
- flush_req,
- flush_total_times);
- else
- ret = qemuMonitorTextGetBlockStatsInfo(mon, dev_name,
- rd_req, rd_bytes,
- rd_total_times,
- wr_req, wr_bytes,
- wr_total_times,
- flush_req,
- flush_total_times);
- return ret;
-}
-
/**
* qemuMonitorGetAllBlockStatsInfo:
}
-/* Return 0 and update @nparams with the number of block stats
- * QEMU supports if success. Return -1 if failure.
- */
-int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
- int *nparams)
-{
- int ret;
- VIR_DEBUG("mon=%p nparams=%p", mon, nparams);
-
- if (!mon) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("monitor must not be NULL"));
- return -1;
- }
-
- if (mon->json)
- ret = qemuMonitorJSONGetBlockStatsParamsNumber(mon, nparams);
- else
- ret = qemuMonitorTextGetBlockStatsParamsNumber(mon, nparams);
-
- return ret;
-}
-
int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
const char *dev_name,
unsigned long long *extent)
qemuMonitorBlockInfoLookup(virHashTablePtr blockInfo,
const char *dev_name);
-int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
- const char *dev_name,
- long long *rd_req,
- long long *rd_bytes,
- long long *rd_total_times,
- long long *wr_req,
- long long *wr_bytes,
- long long *wr_total_times,
- long long *flush_req,
- long long *flush_total_times);
-
typedef struct _qemuBlockStats qemuBlockStats;
typedef qemuBlockStats *qemuBlockStatsPtr;
struct _qemuBlockStats {
bool backingChain)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
- int *nparams);
-
int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
const char *dev_name,
unsigned long long *extent);
}
-int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
- const char *dev_name,
- long long *rd_req,
- long long *rd_bytes,
- long long *rd_total_times,
- long long *wr_req,
- long long *wr_bytes,
- long long *wr_total_times,
- long long *flush_req,
- long long *flush_total_times)
-{
- qemuBlockStats *stats;
- virHashTablePtr blockstats = NULL;
- int ret = -1;
-
- *rd_req = *rd_bytes = -1;
- *wr_req = *wr_bytes = -1;
-
- if (rd_total_times)
- *rd_total_times = -1;
- if (wr_total_times)
- *wr_total_times = -1;
- if (flush_req)
- *flush_req = -1;
- if (flush_total_times)
- *flush_total_times = -1;
-
- if (!(blockstats = virHashCreate(10, virHashValueFree)))
- goto cleanup;
-
- if (qemuMonitorJSONGetAllBlockStatsInfo(mon, blockstats, false) < 0)
- goto cleanup;
-
- if (!(stats = virHashLookup(blockstats, dev_name))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("cannot find statistics for device '%s'"), dev_name);
- goto cleanup;
- }
-
- *rd_req = stats->rd_req;
- *rd_bytes = stats->rd_bytes;
- *wr_req = stats->wr_req;
- *wr_bytes = stats->wr_bytes;
-
- if (rd_total_times)
- *rd_total_times = stats->rd_total_times;
- if (wr_total_times)
- *wr_total_times = stats->wr_total_times;
- if (flush_req)
- *flush_req = stats->flush_req;
- if (flush_total_times)
- *flush_total_times = stats->flush_total_times;
-
- ret = 0;
-
- cleanup:
- virHashFree(blockstats);
- return ret;
-}
-
-
typedef enum {
QEMU_MONITOR_BLOCK_EXTENT_ERROR_OK,
QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOPARENT,
}
-int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
- int *nparams)
-{
- int ret, num = 0;
- size_t i;
- virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
- NULL);
- virJSONValuePtr reply = NULL;
- virJSONValuePtr devices = NULL;
- virJSONValuePtr dev = NULL;
- virJSONValuePtr stats = NULL;
-
- if (!cmd)
- return -1;
-
- ret = qemuMonitorJSONCommand(mon, cmd, &reply);
-
- if (ret == 0)
- ret = qemuMonitorJSONCheckError(cmd, reply);
- if (ret < 0)
- goto cleanup;
- ret = -1;
-
- devices = virJSONValueObjectGet(reply, "return");
- if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("blockstats reply was missing device list"));
- goto cleanup;
- }
-
- dev = virJSONValueArrayGet(devices, 0);
-
- if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("blockstats device entry was not in expected format"));
- goto cleanup;
- }
-
- if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
- stats->type != VIR_JSON_TYPE_OBJECT) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("blockstats stats entry was not in expected format"));
- goto cleanup;
- }
-
- for (i = 0; i < stats->data.object.npairs; i++) {
- const char *key = stats->data.object.pairs[i].key;
-
- if (STREQ(key, "rd_bytes") ||
- STREQ(key, "rd_operations") ||
- STREQ(key, "rd_total_time_ns") ||
- STREQ(key, "wr_bytes") ||
- STREQ(key, "wr_operations") ||
- STREQ(key, "wr_total_time_ns") ||
- STREQ(key, "flush_operations") ||
- STREQ(key, "flush_total_time_ns")) {
- num++;
- } else {
- /* wr_highest_offset is parsed by qemuMonitorJSONGetBlockExtent. */
- if (STRNEQ(key, "wr_highest_offset"))
- VIR_DEBUG("Missed block stat: %s", key);
- }
- }
-
- *nparams = num;
- ret = 0;
-
- cleanup:
- virJSONValueFree(cmd);
- virJSONValueFree(reply);
- return ret;
-}
-
-
static int
qemuMonitorJSONReportBlockExtentError(qemuMonitorBlockExtentError error)
{
int period);
int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
virHashTablePtr table);
-int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
- const char *dev_name,
- long long *rd_req,
- long long *rd_bytes,
- long long *rd_total_times,
- long long *wr_req,
- long long *wr_bytes,
- long long *wr_total_times,
- long long *flush_req,
- long long *flush_total_times);
int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
virHashTablePtr hash,
bool backingChain);
int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
virHashTablePtr stats,
bool backingChain);
-int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
- int *nparams);
int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
const char *dev_name,
unsigned long long *extent);
}
-int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
- const char *dev_name,
- long long *rd_req,
- long long *rd_bytes,
- long long *rd_total_times,
- long long *wr_req,
- long long *wr_bytes,
- long long *wr_total_times,
- long long *flush_req,
- long long *flush_total_times)
-{
- char *info = NULL;
- int ret = -1;
- char *dummy;
- const char *p, *eol;
- int devnamelen = strlen(dev_name);
-
- if (qemuMonitorHMPCommand(mon, "info blockstats", &info) < 0)
- goto cleanup;
-
- /* If the command isn't supported then qemu prints the supported
- * info commands, so the output starts "info ". Since this is
- * unlikely to be the name of a block device, we can use this
- * to detect if qemu supports the command.
- */
- if (strstr(info, "\ninfo ")) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s",
- _("'info blockstats' not supported by this qemu"));
- goto cleanup;
- }
-
- *rd_req = *rd_bytes = -1;
- *wr_req = *wr_bytes = -1;
-
- if (rd_total_times)
- *rd_total_times = -1;
- if (wr_total_times)
- *wr_total_times = -1;
- if (flush_req)
- *flush_req = -1;
- if (flush_total_times)
- *flush_total_times = -1;
-
- /* The output format for both qemu & KVM is:
- * blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=%
- * (repeated for each block device)
- * where '%' is a 64 bit number.
- */
- p = info;
-
- while (*p) {
- /* New QEMU has separate names for host & guest side of the disk
- * and libvirt gives the host side a 'drive-' prefix. The passed
- * in dev_name is the guest side though
- */
- if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX))
- p += strlen(QEMU_DRIVE_HOST_PREFIX);
-
- if (STREQLEN(p, dev_name, devnamelen)
- && p[devnamelen] == ':' && p[devnamelen+1] == ' ') {
-
- eol = strchr(p, '\n');
- if (!eol)
- eol = p + strlen(p);
-
- p += devnamelen+2; /* Skip to first label. */
-
- while (*p) {
- if (STRPREFIX(p, "rd_bytes=")) {
- p += strlen("rd_bytes=");
- if (virStrToLong_ll(p, &dummy, 10, rd_bytes) == -1)
- VIR_DEBUG("error reading rd_bytes: %s", p);
- } else if (STRPREFIX(p, "wr_bytes=")) {
- p += strlen("wr_bytes=");
- if (virStrToLong_ll(p, &dummy, 10, wr_bytes) == -1)
- VIR_DEBUG("error reading wr_bytes: %s", p);
- } else if (STRPREFIX(p, "rd_operations=")) {
- p += strlen("rd_operations=");
- if (virStrToLong_ll(p, &dummy, 10, rd_req) == -1)
- VIR_DEBUG("error reading rd_req: %s", p);
- } else if (STRPREFIX(p, "wr_operations=")) {
- p += strlen("wr_operations=");
- if (virStrToLong_ll(p, &dummy, 10, wr_req) == -1)
- VIR_DEBUG("error reading wr_req: %s", p);
- } else if (rd_total_times &&
- STRPREFIX(p, "rd_total_time_ns=")) {
- p += strlen("rd_total_time_ns=");
- if (virStrToLong_ll(p, &dummy, 10, rd_total_times) == -1)
- VIR_DEBUG("error reading rd_total_times: %s", p);
- } else if (wr_total_times &&
- STRPREFIX(p, "wr_total_time_ns=")) {
- p += strlen("wr_total_time_ns=");
- if (virStrToLong_ll(p, &dummy, 10, wr_total_times) == -1)
- VIR_DEBUG("error reading wr_total_times: %s", p);
- } else if (flush_req &&
- STRPREFIX(p, "flush_operations=")) {
- p += strlen("flush_operations=");
- if (virStrToLong_ll(p, &dummy, 10, flush_req) == -1)
- VIR_DEBUG("error reading flush_req: %s", p);
- } else if (flush_total_times &&
- STRPREFIX(p, "flush_total_time_ns=")) {
- p += strlen("flush_total_time_ns=");
- if (virStrToLong_ll(p, &dummy, 10, flush_total_times) == -1)
- VIR_DEBUG("error reading flush_total_times: %s", p);
- } else {
- VIR_DEBUG("unknown block stat near %s", p);
- }
-
- /* Skip to next label. */
- p = strchr(p, ' ');
- if (!p || p >= eol) break;
- p++;
- }
- ret = 0;
- goto cleanup;
- }
-
- /* Skip to next line. */
- p = strchr(p, '\n');
- if (!p) break;
- p++;
- }
-
- /* If we reach here then the device was not found. */
- virReportError(VIR_ERR_INVALID_ARG,
- _("no stats found for device %s"), dev_name);
-
- cleanup:
- VIR_FREE(info);
- return ret;
-}
-
-int qemuMonitorTextGetBlockStatsParamsNumber(qemuMonitorPtr mon,
- int *nparams)
-{
- char *info = NULL;
- int ret = -1;
- int num = 0;
- const char *p, *eol;
-
- if (qemuMonitorHMPCommand(mon, "info blockstats", &info) < 0)
- goto cleanup;
-
- /* If the command isn't supported then qemu prints the supported
- * info commands, so the output starts "info ". Since this is
- * unlikely to be the name of a block device, we can use this
- * to detect if qemu supports the command.
- */
- if (strstr(info, "\ninfo ")) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s",
- _("'info blockstats' not supported by this qemu"));
- goto cleanup;
- }
-
- /* The output format for both qemu & KVM is:
- * blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=%
- * (repeated for each block device)
- * where '%' is a 64 bit number.
- */
- p = info;
-
- eol = strchr(p, '\n');
- if (!eol)
- eol = p + strlen(p);
-
- /* Skip the device name and following ":", and spaces (e.g.
- * "floppy0: ")
- */
- p = strchr(p, ' ');
-
- while (p && p < eol) {
- if (STRPREFIX(p, " rd_bytes=") ||
- STRPREFIX(p, " wr_bytes=") ||
- STRPREFIX(p, " rd_operations=") ||
- STRPREFIX(p, " wr_operations=") ||
- STRPREFIX(p, " rd_total_time_ns=") ||
- STRPREFIX(p, " wr_total_time_ns=") ||
- STRPREFIX(p, " flush_operations=") ||
- STRPREFIX(p, " flush_total_time_ns=")) {
- num++;
- } else {
- VIR_DEBUG("unknown block stat near %s", p);
- }
-
- /* Skip to next label. */
- p = strchr(p + 1, ' ');
- }
-
- *nparams = num;
- ret = 0;
-
- cleanup:
- VIR_FREE(info);
- return ret;
-}
-
int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
const char *dev_name ATTRIBUTE_UNUSED,
unsigned long long *extent ATTRIBUTE_UNUSED)
int qemuMonitorTextGetAllBlockStatsInfo(qemuMonitorPtr mon,
virHashTablePtr hash);
-int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
- const char *dev_name,
- long long *rd_req,
- long long *rd_bytes,
- long long *rd_total_times,
- long long *wr_req,
- long long *wr_bytes,
- long long *wr_total_times,
- long long *flush_req,
- long long *flush_total_times);
-int qemuMonitorTextGetBlockStatsParamsNumber(qemuMonitorPtr mon,
- int *nparams);
int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon,
const char *dev_name,
unsigned long long *extent);