With this patch, block write threshold events delivered by qemu are converted into libvirt events.
FIXME: Qemu reports stats based on node name, but my plan is to rely on a patch where qemu auto-assigns node names rather than libvirt having to create and track it all. However, there's still the matter that libvirt needs to map a node name back to the right host resource. I tested this patch using a qemu hack patch: https://lists.gnu.org/archive/html/qemu-devel/2015-06/msg02858.html which reported the device name for the active layer node, but the active layer node is the guest view, not the host view. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONHandleBlockWriteThreshold): New function. * src/qemu/qemu_monitor.c (qemuMonitorEmitBlockThreshold): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorEmitBlockThreshold): Likewise. * src/qemu/qemu_process.c (qemuProcessHandleBlockThreshold): Likewise. Signed-off-by: Eric Blake <ebl...@redhat.com> --- src/qemu/qemu_monitor.c | 14 ++++++++++++++ src/qemu/qemu_monitor.h | 11 +++++++++++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_process.c | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 33600f0..27e5a32 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1426,6 +1426,20 @@ qemuMonitorEmitBlockJob(qemuMonitorPtr mon, } +int qemuMonitorEmitBlockThreshold(qemuMonitorPtr mon, + const char *diskAlias, + unsigned long long threshold, + unsigned long long length) +{ + int ret = -1; + VIR_DEBUG("mon=%p", mon); + + QEMU_MONITOR_CALLBACK(mon, ret, domainBlockThreshold, mon->vm, + diskAlias, threshold, length); + return ret; +} + + int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon, unsigned long long actual) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d30b514..381c0a6 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -146,6 +146,12 @@ typedef int (*qemuMonitorDomainBlockJobCallback)(qemuMonitorPtr mon, int type, int status, void *opaque); +typedef int (*qemuMonitorDomainBlockThresholdCallback)(qemuMonitorPtr mon, + virDomainObjPtr vm, + const char *diskAlias, + unsigned long long threshold, + unsigned long long length, + void *opaque); typedef int (*qemuMonitorDomainTrayChangeCallback)(qemuMonitorPtr mon, virDomainObjPtr vm, const char *devAlias, @@ -200,6 +206,7 @@ struct _qemuMonitorCallbacks { qemuMonitorDomainIOErrorCallback domainIOError; qemuMonitorDomainGraphicsCallback domainGraphics; qemuMonitorDomainBlockJobCallback domainBlockJob; + qemuMonitorDomainBlockThresholdCallback domainBlockThreshold; qemuMonitorDomainTrayChangeCallback domainTrayChange; qemuMonitorDomainPMWakeupCallback domainPMWakeup; qemuMonitorDomainPMSuspendCallback domainPMSuspend; @@ -296,6 +303,10 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon, const char *diskAlias, int type, int status); +int qemuMonitorEmitBlockThreshold(qemuMonitorPtr mon, + const char *diskAlias, + unsigned long long threshold, + unsigned long long length); int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon, unsigned long long actual); int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 13c57d2..8dd1279 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -77,6 +77,8 @@ static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr d static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data); +static void qemuMonitorJSONHandleBlockWriteThreshold(qemuMonitorPtr mon, + virJSONValuePtr data); static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data); @@ -95,6 +97,7 @@ static qemuEventHandler eventHandlers[] = { { "BLOCK_JOB_CANCELLED", qemuMonitorJSONHandleBlockJobCanceled, }, { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, }, { "BLOCK_JOB_READY", qemuMonitorJSONHandleBlockJobReady, }, + { "BLOCK_WRITE_THRESHOLD", qemuMonitorJSONHandleBlockWriteThreshold, }, { "DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted, }, { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, }, { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, }, @@ -845,6 +848,36 @@ qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, VIR_DOMAIN_BLOCK_JOB_READY); } + +static void +qemuMonitorJSONHandleBlockWriteThreshold(qemuMonitorPtr mon, + virJSONValuePtr data) +{ + const char *device; + unsigned long long offset = 0, len = 0; + + /* TODO: Once we support node names for more than just the active + * layer, we will need to map this into 'vda[1]' notation. */ + if ((device = virJSONValueObjectGetString(data, "node-name")) == NULL) { + VIR_WARN("missing device in block threshold event"); + goto out; + } + + if (virJSONValueObjectGetNumberUlong(data, "write-threshold", + &offset) < 0) { + VIR_WARN("missing threshold in block threshold event"); + goto out; + } + + if (virJSONValueObjectGetNumberUlong(data, "amount-exceeded", &len) < 0) { + VIR_WARN("missing len in block threshold event"); + goto out; + } + + out: + qemuMonitorEmitBlockThreshold(mon, device, offset, len); +} + static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 64ee049..3109c80 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1037,6 +1037,39 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, static int +qemuProcessHandleBlockThreshold(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + const char *diskAlias, + unsigned long long threshold, + unsigned long long length, + void *opaque) +{ + virQEMUDriverPtr driver = opaque; + virDomainDiskDefPtr disk; + virObjectEventPtr event = NULL; + + virObjectLock(vm); + + VIR_DEBUG("Block threshold for device %s (domain: %p,%s) threshold %llu " + "length %llu", diskAlias, vm, vm->def->name, threshold, length); + + if (!(disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias))) + goto cleanup; + + /* TODO: Once we support node names for more than just the active + * layer, we will need to map this into 'vda[1]' notation. */ + event = virDomainEventWriteThresholdNewFromObj(vm, disk->dst, threshold, + length); + + cleanup: + virObjectUnlock(vm); + if (event) + qemuDomainEventQueue(driver, event); + return 0; +} + + +static int qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED, virDomainObjPtr vm, int phase, @@ -1495,6 +1528,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .domainIOError = qemuProcessHandleIOError, .domainGraphics = qemuProcessHandleGraphics, .domainBlockJob = qemuProcessHandleBlockJob, + .domainBlockThreshold = qemuProcessHandleBlockThreshold, .domainTrayChange = qemuProcessHandleTrayChange, .domainPMWakeup = qemuProcessHandlePMWakeup, .domainPMSuspend = qemuProcessHandlePMSuspend, -- 2.4.2 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list