[libvirt] [RFC PATCHv2 6/8] threshold: add threshold event handling in qemu

Eric Blake eblake at redhat.com
Fri Jun 12 19:29:30 UTC 2015


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 <eblake at 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




More information about the libvir-list mailing list