]> xenbits.xensource.com Git - libvirt.git/commitdiff
startupPolicy: Emit event on disk source dropping
authorMichal Privoznik <mprivozn@redhat.com>
Tue, 18 Oct 2011 14:15:42 +0000 (16:15 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 25 Oct 2011 07:27:10 +0000 (09:27 +0200)
If a disk source gets dropped because it is not accessible,
mgmt application might want to be informed about this. Therefore
we need to emit an event. The event presented in this patch
is however a bit superset of what written above. The reason is simple:
an intention to be easily expanded, e.g. on 'user ejected disk
in guest' events. Therefore, callback gets source string and disk alias
(which should be unique among a domain) and reason (an integer);

14 files changed:
daemon/remote.c
examples/domain-events/events-c/event-test.c
examples/domain-events/events-python/event-test.py
include/libvirt/libvirt.h.in
python/libvirt-override-virConnect.py
python/libvirt-override.c
src/conf/domain_event.c
src/conf/domain_event.h
src/libvirt_private.syms
src/qemu/qemu_domain.c
src/qemu/qemu_process.c
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs

index 550bed4c272555ad2b97689bb2e9b21a7c131c98..9d7016398dbdd7b7e5a020df78efa68598fc20e1 100644 (file)
@@ -451,6 +451,56 @@ static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSE
 }
 
 
+static int remoteRelayDomainEventDiskChange(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                            virDomainPtr dom,
+                                            const char *oldSrcPath,
+                                            const char *newSrcPath,
+                                            const char *devAlias,
+                                            int reason,
+                                            void *opaque)
+{
+    virNetServerClientPtr client = opaque;
+    remote_domain_event_disk_change_msg data;
+    char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;
+
+    if (!client)
+        return -1;
+
+    VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d",
+              dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason);
+
+    /* build return data */
+    memset(&data, 0, sizeof data);
+    if (oldSrcPath &&
+        ((VIR_ALLOC(oldSrcPath_p) < 0) ||
+         !(*oldSrcPath_p = strdup(oldSrcPath))))
+        goto mem_error;
+
+    if (newSrcPath &&
+        ((VIR_ALLOC(newSrcPath_p) < 0) ||
+         !(*newSrcPath_p = strdup(newSrcPath))))
+        goto mem_error;
+
+    data.oldSrcPath = oldSrcPath_p;
+    data.newSrcPath = newSrcPath_p;
+    if (!(data.devAlias = strdup(devAlias)))
+        goto mem_error;
+    data.reason = reason;
+
+    make_nonnull_domain(&data.dom, dom);
+
+    remoteDispatchDomainEventSend(client, remoteProgram,
+                                  REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
+                                  (xdrproc_t)xdr_remote_domain_event_disk_change_msg, &data);
+
+    return 0;
+
+mem_error:
+    virReportOOMError();
+    return -1;
+}
+
+
 static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -461,6 +511,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
+    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
 };
 
 verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
index 6a3ed26ab4d5ab82eb67b99eb286cb6eae2ae688..7c9922265a29b55dcc29b2adc08242ec7e14fdd2 100644 (file)
@@ -285,6 +285,25 @@ static int myDomainEventControlErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED
 }
 
 
+const char *diskChangeReasonStrings[] = {
+    "startupPolicy", /* 0 */
+    /* add new reason here */
+};
+static int myDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                           virDomainPtr dom,
+                                           const char *oldSrcPath,
+                                           const char *newSrcPath,
+                                           const char *devAlias,
+                                           int reason,
+                                           void *opaque ATTRIBUTE_UNUSED)
+{
+    printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom),
+           oldSrcPath, newSrcPath, devAlias, diskChangeReasonStrings[reason]);
+    return 0;
+}
+
+
 static void myFreeFunc(void *opaque)
 {
     char *str = opaque;
@@ -319,6 +338,7 @@ int main(int argc, char **argv)
     int callback6ret = -1;
     int callback7ret = -1;
     int callback8ret = -1;
+    int callback9ret = -1;
     struct sigaction action_stop;
 
     memset(&action_stop, 0, sizeof action_stop);
@@ -382,6 +402,11 @@ int main(int argc, char **argv)
                                                     VIR_DOMAIN_EVENT_ID_CONTROL_ERROR,
                                                     VIR_DOMAIN_EVENT_CALLBACK(myDomainEventControlErrorCallback),
                                                     strdup("callback control error"), myFreeFunc);
+    callback9ret = virConnectDomainEventRegisterAny(dconn,
+                                                    NULL,
+                                                    VIR_DOMAIN_EVENT_ID_DISK_CHANGE,
+                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDiskChangeCallback),
+                                                    strdup("disk change"), myFreeFunc);
 
     if ((callback1ret != -1) &&
         (callback2ret != -1) &&
@@ -389,7 +414,8 @@ int main(int argc, char **argv)
         (callback4ret != -1) &&
         (callback5ret != -1) &&
         (callback6ret != -1) &&
-        (callback7ret != -1)) {
+        (callback7ret != -1) &&
+        (callback9ret != -1)) {
         while (run) {
             if (virEventRunDefaultImpl() < 0) {
                 virErrorPtr err = virGetLastError();
@@ -406,6 +432,7 @@ int main(int argc, char **argv)
         virConnectDomainEventDeregisterAny(dconn, callback5ret);
         virConnectDomainEventDeregisterAny(dconn, callback6ret);
         virConnectDomainEventDeregisterAny(dconn, callback7ret);
+        virConnectDomainEventDeregisterAny(dconn, callback9ret);
         if (callback8ret != -1)
             virConnectDomainEventDeregisterAny(dconn, callback8ret);
     }
index 4df9b981b08e10120c0e30f62437326cf7274ec0..9628f6e4ad8639bb8799baf0659a3ee03999d469 100644 (file)
@@ -469,6 +469,9 @@ def myDomainEventIOErrorCallback(conn, dom, srcpath, devalias, action, opaque):
 def myDomainEventGraphicsCallback(conn, dom, phase, localAddr, remoteAddr, authScheme, subject, opaque):
     print "myDomainEventGraphicsCallback: Domain %s(%s) %d %s" % (dom.name(), dom.ID(), phase, authScheme)
 
+def myDomainEventDiskChangeCallback(conn, dom, oldSrcPath, newSrcPath, devAlias, reason, opaque):
+    print "myDomainEventDiskChangeCallback: Domain %s(%s) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s" % (
+            dom.name(), dom.ID(), oldSrcPath, newSrcPath, devAlias, reason)
 def usage(out=sys.stderr):
     print >>out, "usage: "+os.path.basename(sys.argv[0])+" [-hdl] [uri]"
     print >>out, "   uri will default to qemu:///system"
@@ -526,6 +529,7 @@ def main():
     vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR, myDomainEventIOErrorCallback, None)
     vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG, myDomainEventWatchdogCallback, None)
     vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, myDomainEventGraphicsCallback, None)
+    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DISK_CHANGE, myDomainEventDiskChangeCallback, None)
 
     # The rest of your app would go here normally, but for sake
     # of demo we'll just go to sleep. The other option is to
index 361881a018da9d18c1a2164917fadda7eb9a33a3..7102bce54e1e8182b96b5597e0d76f8a84f73263 100644 (file)
@@ -2995,6 +2995,41 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
                                                       int status,
                                                       void *opaque);
 
+/**
+ * virConnectDomainEventDisChangeReason:
+ *
+ * The reason describing why this callback is called
+ */
+typedef enum {
+    VIR_DOMAIN_DISK_CHANGE_MISSING_ON_START = 0, /* oldSrcPath is set */
+} virConnectDomainEventDiskChangeReason;
+
+/**
+ * virConnectDomainEventDiskChangeCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @oldSrcPath: old source path
+ * @newSrcPath: new source path
+ * @reason: reason why this callback was called; any of
+ *          virConnectDomainEventDiskChangeReason
+ * @opaque: application specified data
+ *
+ * This callback occurs when disk gets changed. However,
+ * not all @reason will cause both @oldSrcPath and @newSrcPath
+ * to be non-NULL. Please see virConnectDomainEventDiskChangeReason
+ * for more details.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_IO_ERROR with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventDiskChangeCallback)(virConnectPtr conn,
+                                                       virDomainPtr dom,
+                                                       const char *oldSrcPath,
+                                                       const char *newSrcPath,
+                                                       const char *devAlias,
+                                                       int reason,
+                                                       void *opaque);
+
 /**
  * VIR_DOMAIN_EVENT_CALLBACK:
  *
@@ -3014,6 +3049,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON = 6, /* virConnectDomainEventIOErrorReasonCallback */
     VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7,   /* virConnectDomainEventGenericCallback */
     VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8,       /* virConnectDomainEventBlockJobCallback */
+    VIR_DOMAIN_EVENT_ID_DISK_CHANGE = 9,     /* virConnectDomainEventDiskChangeCallback */
 
     /*
      * NB: this enum value will increase over time as new events are
index 65b53420c6e1ba7bd05992ff9423fa22d19efadf..b908b32dfb28ee900d81b17ef7566d03942f416c 100644 (file)
         except AttributeError:
             pass
 
+    def _dispatchDomainEventDiskChangeCallback(self, dom, oldSrcPath, newSrcPath, devAlias, reason, cbData):
+        """Dispatches event to python user domain diskChange event callbacks
+        """
+        cb = cbData["cb"]
+        opaque = cbData["opaque"]
+
+        cb(self, virDomain(self, _obj=dom), oldSrcPath, newSrcPath, devAlias, reason, opaque)
+        return 0;
+
     def domainEventDeregisterAny(self, callbackID):
         """Removes a Domain Event Callback. De-registering for a
            domain callback will disable delivery of this event type """
index 523c03bf486c6e7807a026d0bc57bef8e2fd3a84..1759baea1921b7826144c9d479a453a0ef07bf4e 100644 (file)
@@ -4374,6 +4374,56 @@ libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSE
     return ret;
 }
 
+static int
+libvirt_virConnectDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                                virDomainPtr dom,
+                                                const char *oldSrcPath,
+                                                const char *newSrcPath,
+                                                const char *devAlias,
+                                                int reason,
+                                                void *opaque)
+{
+    PyObject *pyobj_cbData = (PyObject*)opaque;
+    PyObject *pyobj_dom;
+    PyObject *pyobj_ret;
+    PyObject *pyobj_conn;
+    PyObject *dictKey;
+    int ret = -1;
+
+    LIBVIRT_ENSURE_THREAD_STATE;
+    /* Create a python instance of this virDomainPtr */
+    virDomainRef(dom);
+
+    pyobj_dom = libvirt_virDomainPtrWrap(dom);
+    Py_INCREF(pyobj_cbData);
+
+    dictKey = libvirt_constcharPtrWrap("conn");
+    pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+    Py_DECREF(dictKey);
+
+    /* Call the Callback Dispatcher */
+    pyobj_ret = PyObject_CallMethod(pyobj_conn,
+                                    (char*)"_dispatchDomainEventDiskChangeCallback",
+                                    (char*)"OsssiO",
+                                    pyobj_dom,
+                                    oldSrcPath, newSrcPath,
+                                    devAlias, reason, pyobj_cbData);
+
+    Py_DECREF(pyobj_cbData);
+    Py_DECREF(pyobj_dom);
+
+    if(!pyobj_ret) {
+        DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+        PyErr_Print();
+    } else {
+        Py_DECREF(pyobj_ret);
+        ret = 0;
+    }
+
+    LIBVIRT_RELEASE_THREAD_STATE;
+    return ret;
+}
+
 static PyObject *
 libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
                                          PyObject * args)
@@ -4431,6 +4481,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
     case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
         cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBlockJobCallback);
         break;
+    case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
+        cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventDiskChangeCallback);
+        break;
     }
 
     if (!cb) {
index f712c3466a796f4ada8f27d7f6385e031f1d4c3a..a04b9d08605ca64c603a04b52d693992b031e8f2 100644 (file)
@@ -88,6 +88,12 @@ struct _virDomainEvent {
             int type;
             int status;
         } blockJob;
+        struct {
+            char *oldSrcPath;
+            char *newSrcPath;
+            char *devAlias;
+            int reason;
+        } diskChange;
     } data;
 };
 
@@ -509,6 +515,12 @@ void virDomainEventFree(virDomainEventPtr event)
     case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
         VIR_FREE(event->data.blockJob.path);
         break;
+
+    case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
+        VIR_FREE(event->data.diskChange.oldSrcPath);
+        VIR_FREE(event->data.diskChange.newSrcPath);
+        VIR_FREE(event->data.diskChange.devAlias);
+        break;
     }
 
     VIR_FREE(event->dom.name);
@@ -961,6 +973,61 @@ virDomainEventPtr virDomainEventControlErrorNewFromObj(virDomainObjPtr obj)
     return ev;
 }
 
+static virDomainEventPtr
+virDomainEventDiskChangeNew(int id, const char *name,
+                            unsigned char *uuid,
+                            const char *oldSrcPath,
+                            const char *newSrcPath,
+                            const char *devAlias, int reason)
+{
+    virDomainEventPtr ev =
+        virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_DISK_CHANGE,
+                                  id, name, uuid);
+
+    if (ev) {
+        if (!(ev->data.diskChange.devAlias = strdup(devAlias)))
+            goto error;
+
+        if (oldSrcPath &&
+            !(ev->data.diskChange.oldSrcPath = strdup(oldSrcPath)))
+            goto error;
+
+        if (newSrcPath &&
+            !(ev->data.diskChange.newSrcPath = strdup(newSrcPath)))
+            goto error;
+
+        ev->data.diskChange.reason = reason;
+    }
+
+    return ev;
+
+error:
+    virReportOOMError();
+    virDomainEventFree(ev);
+    return NULL;
+}
+
+virDomainEventPtr virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj,
+                                                     const char *oldSrcPath,
+                                                     const char *newSrcPath,
+                                                     const char *devAlias,
+                                                     int reason)
+{
+    return virDomainEventDiskChangeNew(obj->def->id, obj->def->name,
+                                       obj->def->uuid, oldSrcPath,
+                                       newSrcPath, devAlias, reason);
+}
+
+virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
+                                                     const char *oldSrcPath,
+                                                     const char *newSrcPath,
+                                                     const char *devAlias,
+                                                     int reason)
+{
+    return virDomainEventDiskChangeNew(dom->id, dom->name, dom->uuid,
+                                       oldSrcPath, newSrcPath,
+                                       devAlias, reason);
+}
 
 /**
  * virDomainEventQueuePop:
@@ -1104,6 +1171,15 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
                                                     cbopaque);
         break;
 
+    case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
+        ((virConnectDomainEventDiskChangeCallback)cb)(conn, dom,
+                                                      event->data.diskChange.oldSrcPath,
+                                                      event->data.diskChange.newSrcPath,
+                                                      event->data.diskChange.devAlias,
+                                                      event->data.diskChange.reason,
+                                                      cbopaque);
+        break;
+
     default:
         VIR_WARN("Unexpected event ID %d", event->eventID);
         break;
index 08930ed23ef2759110b416d0a28447ff42dbfbf7..3ba418e95b551ff6366a65eb4db38c16ccdf38cd 100644 (file)
@@ -179,6 +179,17 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
                                                     int type,
                                                     int status);
 
+virDomainEventPtr virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj,
+                                                     const char *oldSrcPath,
+                                                     const char *newSrcPath,
+                                                     const char *devAlias,
+                                                     int reason);
+virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
+                                                     const char *oldSrcPath,
+                                                     const char *newSrcPath,
+                                                     const char *devAlias,
+                                                     int reason);
+
 int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
                             virDomainEventPtr event);
 
index 74a35db07324865de0506614ec345127fa42eb34..3f97e23c9f832461c5418aa0873631e3f99eb21d 100644 (file)
@@ -481,6 +481,8 @@ virDomainEventCallbackListRemoveConn;
 virDomainEventCallbackListRemoveID;
 virDomainEventControlErrorNewFromDom;
 virDomainEventControlErrorNewFromObj;
+virDomainEventDiskChangeNewFromDom;
+virDomainEventDiskChangeNewFromObj;
 virDomainEventDispatch;
 virDomainEventDispatchDefaultFunc;
 virDomainEventFree;
index 7fbdfa13c9bdd9fa654b9b2b4e7112f2b689da5f..198ebcc9e44a04692c1cf2e3d57752ed9e8cd24d 100644 (file)
@@ -35,6 +35,7 @@
 #include "ignore-value.h"
 #include "uuid.h"
 #include "virfile.h"
+#include "domain_event.h"
 
 #include <sys/time.h>
 #include <fcntl.h>
@@ -1619,6 +1620,7 @@ qemuDomainCheckDiskPresence(struct qemud_driver *driver,
     int accessRet;
     virDomainDiskDefPtr disk;
     char uuid[VIR_UUID_STRING_BUFLEN] ATTRIBUTE_UNUSED;
+    virDomainEventPtr event = NULL;
 
     virUUIDFormat(vm->def->uuid, uuid);
 
@@ -1666,6 +1668,11 @@ qemuDomainCheckDiskPresence(struct qemud_driver *driver,
                   "due to not accessible source '%s'",
                   disk->dst, vm->def->name, uuid, disk->src);
 
+        event = virDomainEventDiskChangeNewFromObj(vm, disk->src, NULL, disk->info.alias,
+                                                   VIR_DOMAIN_DISK_CHANGE_MISSING_ON_START);
+        if (event)
+            qemuDomainEventQueue(driver, event);
+
         VIR_FREE(disk->src);
     }
 
index 57312238cf99a6549b299f645b048eb8e5fd822b..18c98c6f01054e36eb44c41ece33462f6ad41aca 100644 (file)
@@ -2880,13 +2880,6 @@ int qemuProcessStart(virConnectPtr conn,
                                NULL) < 0)
         goto cleanup;
 
-    if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0)
-        goto cleanup;
-
-    VIR_DEBUG("Checking for CDROM and floppy presence");
-    if (qemuDomainCheckDiskPresence(driver, vm, migrateFrom != NULL) < 0)
-        goto cleanup;
-
     /* If you are using a SecurityDriver with dynamic labelling,
        then generate a security label for isolation */
     VIR_DEBUG("Generating domain security label (if required)");
@@ -2956,6 +2949,13 @@ int qemuProcessStart(virConnectPtr conn,
                                    &priv->qemuCaps) < 0)
         goto cleanup;
 
+    if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0)
+        goto cleanup;
+
+    VIR_DEBUG("Checking for CDROM and floppy presence");
+    if (qemuDomainCheckDiskPresence(driver, vm, migrateFrom != NULL) < 0)
+        goto cleanup;
+
     VIR_DEBUG("Setting up domain cgroup (if required)");
     if (qemuSetupCgroup(driver, vm) < 0)
         goto cleanup;
index 1dea327fb54be68928ba52b1f5a0305297aa030c..e98ebd737e235580029ce30eb0fc77080b60887c 100644 (file)
@@ -228,6 +228,11 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog,
                                virNetClientPtr client,
                                void *evdata, void *opaque);
 
+static void
+remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog,
+                                 virNetClientPtr client,
+                                 void *evdata, void *opaque);
+
 static virNetClientProgramEvent remoteDomainEvents[] = {
     { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
       remoteDomainBuildEventRTCChange,
@@ -265,6 +270,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
       remoteDomainBuildEventBlockJob,
       sizeof(remote_domain_event_block_job_msg),
       (xdrproc_t)xdr_remote_domain_event_block_job_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
+      remoteDomainBuildEventDiskChange,
+      sizeof(remote_domain_event_disk_change_msg),
+      (xdrproc_t)xdr_remote_domain_event_disk_change_msg },
 };
 
 enum virDrvOpenRemoteFlags {
@@ -3327,6 +3336,33 @@ remoteDomainBuildEventControlError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
 }
 
 
+static void
+remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                 virNetClientPtr client ATTRIBUTE_UNUSED,
+                                 void *evdata, void *opaque)
+{
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_disk_change_msg *msg = evdata;
+    virDomainPtr dom;
+    virDomainEventPtr event = NULL;
+
+    dom = get_nonnull_domain(conn, msg->dom);
+    if (!dom)
+        return;
+
+    event = virDomainEventDiskChangeNewFromDom(dom,
+                                               msg->oldSrcPath ? *msg->oldSrcPath : NULL,
+                                               msg->newSrcPath ? *msg->newSrcPath : NULL,
+                                               msg->devAlias,
+                                               msg->reason);
+
+    virDomainFree(dom);
+
+    remoteDomainEventQueue(priv, event);
+}
+
+
 static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
 remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth,
                  unsigned int flags)
index f95253ed7729cefd2cdf20e5778dcca88790bd3c..d135653dd72dd2590a10254d2057df37520932d8 100644 (file)
@@ -2010,6 +2010,14 @@ struct remote_domain_event_block_job_msg {
     int status;
 };
 
+struct remote_domain_event_disk_change_msg {
+    remote_nonnull_domain dom;
+    remote_string oldSrcPath;
+    remote_string newSrcPath;
+    remote_nonnull_string devAlias;
+    int reason;
+};
+
 struct remote_domain_managed_save_args {
     remote_nonnull_domain dom;
     unsigned int flags;
@@ -2546,7 +2554,8 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_SNAPSHOT_GET_PARENT = 244, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_RESET = 245, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN = 246, /* autogen autogen priority:high */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247 /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248 /* skipgen skipgen */
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
index 78944412498bf0bcb1ecd13246e12a2faf1c95b5..8e8b23164c9429ace53e2747a570564ad02e930e 100644 (file)
@@ -1509,6 +1509,13 @@ struct remote_domain_event_block_job_msg {
         int                        type;
         int                        status;
 };
+struct remote_domain_event_disk_change_msg {
+        remote_nonnull_domain      dom;
+        remote_string              oldSrcPath;
+        remote_string              newSrcPath;
+        remote_nonnull_string      devAlias;
+        int                        reason;
+};
 struct remote_domain_managed_save_args {
         remote_nonnull_domain      dom;
         u_int                      flags;