提交 eca96694 编写于 作者: L Lei Li 提交者: Eric Blake

Implement virDomain{Set, Get}BlockIoTune for the qemu driver

Implement the block I/O throttle setting and getting support to qemu
driver.
Signed-off-by: NLei Li <lilei@linux.vnet.ibm.com>
Signed-off-by: NZhi Yong Wu <wuzhy@linux.vnet.ibm.com>
Signed-off-by: NEric Blake <eblake@redhat.com>
上级 6df7ccb1
......@@ -1866,6 +1866,37 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
}
}
/* block I/O throttling */
if (disk->blkdeviotune.total_bytes_sec) {
virBufferAsprintf(&opt, ",bps=%llu",
disk->blkdeviotune.total_bytes_sec);
}
if (disk->blkdeviotune.read_bytes_sec) {
virBufferAsprintf(&opt, ",bps_rd=%llu",
disk->blkdeviotune.read_bytes_sec);
}
if (disk->blkdeviotune.write_bytes_sec) {
virBufferAsprintf(&opt, ",bps_wr=%llu",
disk->blkdeviotune.write_bytes_sec);
}
if (disk->blkdeviotune.total_iops_sec) {
virBufferAsprintf(&opt, ",iops=%llu",
disk->blkdeviotune.total_iops_sec);
}
if (disk->blkdeviotune.read_iops_sec) {
virBufferAsprintf(&opt, ",iops_rd=%llu",
disk->blkdeviotune.read_iops_sec);
}
if (disk->blkdeviotune.write_iops_sec) {
virBufferAsprintf(&opt, ",iops_wr=%llu",
disk->blkdeviotune.write_iops_sec);
}
if (virBufferError(&opt)) {
virReportOOMError();
goto error;
......
......@@ -95,6 +95,8 @@
#define QEMU_NB_MEM_PARAM 3
#define QEMU_NB_BLOCK_IO_TUNE_PARAM 6
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
......@@ -11062,6 +11064,336 @@ cleanup:
return ret;
}
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
const char *disk,
virTypedParameterPtr params,
int nparams,
unsigned int flags)
{
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm = NULL;
qemuDomainObjPrivatePtr priv;
virDomainDefPtr persistentDef = NULL;
virDomainBlockIoTuneInfo info;
char uuidstr[VIR_UUID_STRING_BUFLEN];
const char *device = NULL;
int ret = -1;
int i;
bool isActive;
int idx = -1;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG, -1);
memset(&info, 0, sizeof(info));
qemuDriverLock(driver);
virUUIDFormat(dom->uuid, uuidstr);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
if (!vm) {
qemuReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
}
device = qemuDiskPathToAlias(vm, disk);
if (!device) {
goto cleanup;
}
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
isActive = virDomainObjIsActive(vm);
if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
if (isActive)
flags = VIR_DOMAIN_AFFECT_LIVE;
else
flags = VIR_DOMAIN_AFFECT_CONFIG;
}
if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("domain is not running"));
goto endjob;
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
if (!vm->persistent) {
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("cannot change persistent config of a transient domain"));
goto endjob;
}
if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
goto endjob;
idx = virDomainDiskIndexByName(persistentDef, disk, true);
if (idx < 0)
goto endjob;
}
for (i = 0; i < nparams; i++) {
virTypedParameterPtr param = &params[i];
if (param->type != VIR_TYPED_PARAM_ULLONG) {
qemuReportError(VIR_ERR_INVALID_ARG,
_("expected unsigned long long for parameter %s"),
param->field);
goto endjob;
}
if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC)) {
info.total_bytes_sec = param->value.ul;
} else if (STREQ(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
info.read_bytes_sec = param->value.ul;
} else if (STREQ(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
info.write_bytes_sec = param->value.ul;
} else if (STREQ(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
info.total_iops_sec = param->value.ul;
} else if (STREQ(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
info.read_iops_sec = param->value.ul;
} else if (STREQ(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
info.write_iops_sec = param->value.ul;
} else {
qemuReportError(VIR_ERR_INVALID_ARG,
_("Unrecognized parameter %s"),
param->field);
goto endjob;
}
}
if ((info.total_bytes_sec && info.read_bytes_sec) ||
(info.total_bytes_sec && info.write_bytes_sec)) {
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
_("total and read/write of bytes_sec cannot be set at the same time"));
goto endjob;
}
if ((info.total_iops_sec && info.read_iops_sec) ||
(info.total_iops_sec && info.write_iops_sec)) {
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
_("total and read/write of iops_sec cannot be set at the same time"));
goto endjob;
}
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
priv = vm->privateData;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
qemuDomainObjExitMonitorWithDriver(driver, vm);
}
if (ret < 0)
goto endjob;
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
sa_assert(persistentDef && idx >= 0);
persistentDef->disks[idx]->blkdeviotune = info;
ret = virDomainSaveConfig(driver->configDir, persistentDef);
if (ret < 0) {
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("Write to config file failed"));
goto endjob;
}
}
endjob:
if (qemuDomainObjEndJob(driver, vm) == 0)
vm = NULL;
cleanup:
VIR_FREE(device);
if (vm)
virDomainObjUnlock(vm);
qemuDriverUnlock(driver);
return ret;
}
static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
const char *disk,
virTypedParameterPtr params,
int *nparams,
unsigned int flags)
{
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm = NULL;
qemuDomainObjPrivatePtr priv;
virDomainDefPtr persistentDef = NULL;
virDomainBlockIoTuneInfo reply;
char uuidstr[VIR_UUID_STRING_BUFLEN];
const char *device = NULL;
int ret = -1;
int i;
bool isActive;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG |
VIR_TYPED_PARAM_STRING_OKAY, -1);
/* We don't return strings, and thus trivially support this flag. */
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
qemuDriverLock(driver);
virUUIDFormat(dom->uuid, uuidstr);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
if (!vm) {
qemuReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
}
if ((*nparams) == 0) {
/* Current number of parameters supported by QEMU Block I/O Throttling */
*nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
ret = 0;
goto cleanup;
}
device = qemuDiskPathToAlias(vm, disk);
if (!device) {
goto cleanup;
}
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
isActive = virDomainObjIsActive(vm);
if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
if (isActive)
flags = VIR_DOMAIN_AFFECT_LIVE;
else
flags = VIR_DOMAIN_AFFECT_CONFIG;
}
if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("domain is not running"));
goto endjob;
}
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
priv = vm->privateData;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret < 0)
goto endjob;
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
if (!vm->persistent) {
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("domain is transient"));
goto endjob;
}
if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
goto endjob;
int idx = virDomainDiskIndexByName(vm->def, disk, true);
if (idx < 0)
goto endjob;
reply = persistentDef->disks[idx]->blkdeviotune;
}
for (i = 0; i < QEMU_NB_BLOCK_IO_TUNE_PARAM && i < *nparams; i++) {
virTypedParameterPtr param = &params[i];
param->value.ul = 0;
param->type = VIR_TYPED_PARAM_ULLONG;
switch(i) {
case 0:
if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Field name '%s' too long"),
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC);
goto endjob;
}
param->value.ul = reply.total_bytes_sec;
break;
case 1:
if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Field name '%s' too long"),
VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC);
goto endjob;
}
param->value.ul = reply.read_bytes_sec;
break;
case 2:
if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Field name '%s' too long"),
VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC);
goto endjob;
}
param->value.ul = reply.write_bytes_sec;
break;
case 3:
if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Field name '%s' too long"),
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC);
goto endjob;
}
param->value.ul = reply.total_iops_sec;
break;
case 4:
if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Field name '%s' too long"),
VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC);
goto endjob;
}
param->value.ul = reply.read_iops_sec;
break;
case 5:
if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Field name '%s' too long"),
VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC);
goto endjob;
}
param->value.ul = reply.write_iops_sec;
break;
default:
break;
}
}
if (*nparams > QEMU_NB_BLOCK_IO_TUNE_PARAM)
*nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
ret = 0;
endjob:
if (qemuDomainObjEndJob(driver, vm) == 0)
vm = NULL;
cleanup:
VIR_FREE(device);
if (vm)
virDomainObjUnlock(vm);
qemuDriverUnlock(driver);
return ret;
}
static virDriver qemuDriver = {
.no = VIR_DRV_QEMU,
......@@ -11209,6 +11541,8 @@ static virDriver qemuDriver = {
.domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
.isAlive = qemuIsAlive, /* 0.9.8 */
.nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
.domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
.domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
};
......
......@@ -2582,6 +2582,39 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
return ret;
}
int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info)
{
int ret;
VIR_DEBUG("mon=%p, device=%p, info=%p", mon, device, info);
if (mon->json) {
ret = qemuMonitorJSONSetBlockIoThrottle(mon, device, info);
} else {
ret = qemuMonitorTextSetBlockIoThrottle(mon, device, info);
}
return ret;
}
int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply)
{
int ret;
VIR_DEBUG("mon=%p, device=%p, reply=%p", mon, device, reply);
if (mon->json) {
ret = qemuMonitorJSONGetBlockIoThrottle(mon, device, reply);
} else {
ret = qemuMonitorTextGetBlockIoThrottle(mon, device, reply);
}
return ret;
}
int qemuMonitorVMStatusToPausedReason(const char *status)
{
int st;
......
......@@ -522,6 +522,14 @@ int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
const char *fdname,
bool skipauth);
int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info);
int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply);
/**
* When running two dd process and using <> redirection, we need a
* shell that will not truncate files. These two strings serve that
......
......@@ -3308,3 +3308,179 @@ int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
virJSONValueFree(reply);
return ret;
}
static int
qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
const char *device,
virDomainBlockIoTuneInfoPtr reply)
{
virJSONValuePtr io_throttle;
int ret = -1;
int i;
int found = 0;
io_throttle = virJSONValueObjectGet(result, "return");
if (!io_throttle || io_throttle->type != VIR_JSON_TYPE_ARRAY) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_(" block_io_throttle reply was missing device list"));
goto cleanup;
}
for (i = 0; i < virJSONValueArraySize(io_throttle); i++) {
virJSONValuePtr temp_dev = virJSONValueArrayGet(io_throttle, i);
virJSONValuePtr inserted;
const char *current_dev;
if (!temp_dev || temp_dev->type != VIR_JSON_TYPE_OBJECT) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("block io throttle device entry was not in expected format"));
goto cleanup;
}
if ((current_dev = virJSONValueObjectGetString(temp_dev, "device")) == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("block io throttle device entry was not in expected format"));
goto cleanup;
}
if(STRPREFIX(current_dev, QEMU_DRIVE_HOST_PREFIX))
current_dev += strlen(QEMU_DRIVE_HOST_PREFIX);
if (STREQ(current_dev, device))
continue;
found = 1;
if ((inserted = virJSONValueObjectGet(temp_dev, "inserted")) == NULL ||
inserted->type != VIR_JSON_TYPE_OBJECT) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("block io throttle inserted entry was not in expected format"));
goto cleanup;
}
if (virJSONValueObjectGetNumberUlong(inserted, "bps", &reply->total_bytes_sec) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot read total_bytes_sec"));
goto cleanup;
}
if (virJSONValueObjectGetNumberUlong(inserted, "bps_rd", &reply->read_bytes_sec) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot read read_bytes_sec"));
goto cleanup;
}
if (virJSONValueObjectGetNumberUlong(inserted, "bps_wr", &reply->write_bytes_sec) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot read write_bytes_sec"));
goto cleanup;
}
if (virJSONValueObjectGetNumberUlong(inserted, "iops", &reply->total_iops_sec) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot read total_iops_sec"));
goto cleanup;
}
if (virJSONValueObjectGetNumberUlong(inserted, "iops_rd", &reply->read_iops_sec) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot read read_iops_sec"));
goto cleanup;
}
if (virJSONValueObjectGetNumberUlong(inserted, "iops_wr", &reply->write_iops_sec) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot read write_iops_sec"));
goto cleanup;
}
break;
}
if (!found) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find throttling info for device '%s'"),
device);
goto cleanup;
}
ret = 0;
cleanup:
return ret;
}
int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info)
{
int ret = -1;
virJSONValuePtr cmd = NULL;
virJSONValuePtr result = NULL;
cmd = qemuMonitorJSONMakeCommand("block_set_io_throttle",
"s:device", device,
"U:bps", info->total_bytes_sec,
"U:bps_rd", info->read_bytes_sec,
"U:bps_wr", info->write_bytes_sec,
"U:iops", info->total_iops_sec,
"U:iops_rd", info->read_iops_sec,
"U:iops_wr", info->write_iops_sec,
NULL);
if (!cmd)
return -1;
ret = qemuMonitorJSONCommand(mon, cmd, &result);
if (ret == 0 && virJSONValueObjectHasKey(result, "error")) {
if (qemuMonitorJSONHasError(result, "DeviceNotActive"))
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("No active operation on device: %s"), device);
else if (qemuMonitorJSONHasError(result, "NotSupported"))
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("Operation is not supported for device: %s"), device);
else
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unexpected error"));
ret = -1;
}
virJSONValueFree(cmd);
virJSONValueFree(result);
return ret;
}
int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply)
{
int ret = -1;
virJSONValuePtr cmd = NULL;
virJSONValuePtr result = NULL;
cmd = qemuMonitorJSONMakeCommand("query-block", NULL);
if (!cmd) {
return -1;
}
ret = qemuMonitorJSONCommand(mon, cmd, &result);
if (ret == 0 && virJSONValueObjectHasKey(result, "error")) {
if (qemuMonitorJSONHasError(result, "DeviceNotActive"))
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("No active operation on device: %s"), device);
else if (qemuMonitorJSONHasError(result, "NotSupported"))
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("Operation is not supported for device: %s"), device);
else
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unexpected error"));
ret = -1;
}
if (ret == 0)
ret = qemuMonitorJSONBlockIoThrottleInfo(result, device, reply);
virJSONValueFree(cmd);
virJSONValueFree(result);
return ret;
}
......@@ -257,4 +257,12 @@ int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
const char *fdname,
bool skipauth);
int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info);
int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply);
#endif /* QEMU_MONITOR_JSON_H */
......@@ -812,7 +812,7 @@ int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
if (!eol)
eol = p + strlen(p);
p += devnamelen + 2; /*Skip to first label. */
p += devnamelen + 2; /* Skip to first label. */
while (*p) {
if (STRPREFIX(p, "removable=")) {
......@@ -3462,3 +3462,152 @@ cleanup:
VIR_FREE(cmd);
return ret;
}
int qemuMonitorTextSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info)
{
char *cmd = NULL;
char *result = NULL;
int ret = 0;
const char *cmd_name = NULL;
/* For the not specified fields, 0 by default */
cmd_name = "block_set_io_throttle";
ret = virAsprintf(&cmd, "%s %s %llu %llu %llu %llu %llu %llu", cmd_name,
device, info->total_bytes_sec, info->read_bytes_sec,
info->write_bytes_sec, info->total_iops_sec,
info->read_iops_sec, info->write_iops_sec);
if (ret < 0) {
virReportOOMError();
return -1;
}
if (qemuMonitorHMPCommand(mon, cmd, &result) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot run monitor command"));
ret = -1;
goto cleanup;
}
if (qemuMonitorTextCommandNotFound(cmd_name, result)) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("Command '%s' is not found"), cmd_name);
ret = -1;
goto cleanup;
}
cleanup:
VIR_FREE(cmd);
VIR_FREE(result);
return ret;
}
static int
qemuMonitorTextParseBlockIoThrottle(const char *result,
const char *device,
virDomainBlockIoTuneInfoPtr reply)
{
char *dummy = NULL;
int ret = -1;
const char *p, *eol;
int devnamelen = strlen(device);
p = result;
while (*p) {
if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX))
p += strlen(QEMU_DRIVE_HOST_PREFIX);
if (STREQLEN(p, device, 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, "bps=")) {
p += strlen("bps=");
if (virStrToLong_ull(p, &dummy, 10, &reply->total_bytes_sec) == -1)
VIR_DEBUG("error reading total_bytes_sec: %s", p);
} else if (STRPREFIX(p, "bps_rd=")) {
p += strlen("bps_rd=");
if (virStrToLong_ull(p, &dummy, 10, &reply->read_bytes_sec) == -1)
VIR_DEBUG("error reading read_bytes_sec: %s", p);
} else if (STRPREFIX(p, "bps_wr=")) {
p += strlen("bps_wr=");
if (virStrToLong_ull(p, &dummy, 10, &reply->write_bytes_sec) == -1)
VIR_DEBUG("error reading write_bytes_sec: %s", p);
} else if (STRPREFIX(p, "iops=")) {
p += strlen("iops=");
if (virStrToLong_ull(p, &dummy, 10, &reply->total_iops_sec) == -1)
VIR_DEBUG("error reading total_iops_sec: %s", p);
} else if (STRPREFIX(p, "iops_rd=")) {
p += strlen("iops_rd=");
if (virStrToLong_ull(p, &dummy, 10, &reply->read_iops_sec) == -1)
VIR_DEBUG("error reading read_iops_sec: %s", p);
} else if (STRPREFIX(p, "iops_wr=")) {
p += strlen("iops_wr=");
if (virStrToLong_ull(p, &dummy, 10, &reply->write_iops_sec) == -1)
VIR_DEBUG("error reading write_iops_sec: %s", p);
} else {
VIR_DEBUG(" unknown block info %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++;
}
qemuReportError(VIR_ERR_INVALID_ARG,
_("No info for device '%s'"), device);
cleanup:
return ret;
}
int qemuMonitorTextGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply)
{
char *result = NULL;
int ret = 0;
const char *cmd_name = "info block";
if (qemuMonitorHMPCommand(mon, cmd_name, &result) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot run monitor command"));
ret = -1;
goto cleanup;
}
if (qemuMonitorTextCommandNotFound(cmd_name, result)) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("Command '%s' is not found"), cmd_name);
ret = -1;
goto cleanup;
}
ret = qemuMonitorTextParseBlockIoThrottle(result, device, reply);
cleanup:
VIR_FREE(result);
return ret;
}
......@@ -250,4 +250,12 @@ int qemuMonitorTextOpenGraphics(qemuMonitorPtr mon,
const char *fdname,
bool skipauth);
int qemuMonitorTextSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info);
int qemuMonitorTextGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply);
#endif /* QEMU_MONITOR_TEXT_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册