When an operation started by virDomainBlockPull completes (either with
success or with failure), raise an event to indicate the final status. This
allows an API user to avoid polling on virDomainGetBlockJobInfo if they would
prefer to use the event mechanism.
* daemon/remote.c: Dispatch events to client
* include/libvirt/libvirt.h.in: Define event ID and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle the new event
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block_stream completion and emit a libvirt block pull event
* src/remote/remote_driver.c: Receive and dispatch events to application
* src/remote/remote_protocol.x: Wire protocol definition for the event
* src/remote_protocol-structs: structure definitions for protocol verification
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_STREAM_COMPLETED event
from QEMU monitor
Signed-off-by: Adam Litke <agl(a)us.ibm.com>
---
daemon/remote.c | 31 ++++++++++++++++++
include/libvirt/libvirt.h.in | 29 +++++++++++++++++
python/libvirt-override-virConnect.py | 12 +++++++
python/libvirt-override.c | 52 ++++++++++++++++++++++++++++++
src/conf/domain_event.c | 56 +++++++++++++++++++++++++++++++++
src/conf/domain_event.h | 9 +++++-
src/libvirt_private.syms | 2 +
src/qemu/qemu_monitor.c | 13 +++++++
src/qemu/qemu_monitor.h | 10 ++++++
src/qemu/qemu_monitor_json.c | 40 +++++++++++++++++++++++
src/qemu/qemu_process.c | 31 ++++++++++++++++++
src/remote/remote_driver.c | 31 ++++++++++++++++++
src/remote/remote_protocol.x | 10 +++++-
src/remote_protocol-structs | 8 ++++-
14 files changed, 331 insertions(+), 3 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index b471abc..939044c 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -339,6 +339,36 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn
ATTRIBUTE_UNUSED,
return 0;
}
+static int remoteRelayDomainEventBlockJob(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_block_job_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i",
+ dom->name, dom->id, path, type, status);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ make_nonnull_domain(&data.dom, dom);
+ data.path = (char*)path;
+ data.type = type;
+ data.status = status;
+
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
+ (xdrproc_t)xdr_remote_domain_event_block_job_msg,
&data);
+
+ return 0;
+}
+
static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
@@ -373,6 +403,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] =
{
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 23947c7..d215655 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2735,6 +2735,34 @@ typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr
conn,
void *opaque);
/**
+ * virConnectDomainEventBlockJobStatus:
+ *
+ * The final status of a virDomainBlockPullAll() operation
+ */
+typedef enum {
+ VIR_DOMAIN_BLOCK_JOB_COMPLETED = 0,
+ VIR_DOMAIN_BLOCK_JOB_FAILED = 1,
+} virConnectDomainEventBlockJobStatus;
+
+/**
+ * virConnectDomainEventBlockJobCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @path: fully-qualified filename of the affected disk
+ * @type: type of block job (virDomainBlockJobType)
+ * @status: final status of the operation (virConnectDomainEventBlockJobStatus)
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_BLOCK_JOB with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ void *opaque);
+
+/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
* Used to cast the event specific callback into the generic one
@@ -2752,6 +2780,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_GRAPHICS = 5, /* virConnectDomainEventGraphicsCallback */
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 */
/*
* NB: this enum value will increase over time as new events are
diff --git a/python/libvirt-override-virConnect.py
b/python/libvirt-override-virConnect.py
index eeeedf9..65b5342 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -113,6 +113,18 @@
authScheme, subject, opaque)
return 0
+ def dispatchDomainEventBlockPullCallback(self, dom, path, type, status, cbData):
+ """Dispatches events to python user domain blockJob event
callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), path, type, status, opaque)
+ return 0
+ except AttributeError:
+ pass
+
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index e89bc97..db76315 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -3582,6 +3582,55 @@ libvirt_virConnectDomainEventGraphicsCallback(virConnectPtr conn
ATTRIBUTE_UNUSE
return ret;
}
+static int
+libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ 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*)"dispatchDomainEventBlockPullCallback",
+ (char*)"OsiiO",
+ pyobj_dom, path, type, status, pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ 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)
@@ -3636,6 +3685,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject *
self,
case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventGenericCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBlockJobCallback);
+ break;
}
if (!cb) {
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index c435484..dda7e74 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -83,6 +83,11 @@ struct _virDomainEvent {
char *authScheme;
virDomainEventGraphicsSubjectPtr subject;
} graphics;
+ struct {
+ char *path;
+ int type;
+ int status;
+ } blockJob;
} data;
};
@@ -499,6 +504,11 @@ void virDomainEventFree(virDomainEventPtr event)
}
VIR_FREE(event->data.graphics.subject);
}
+ break;
+
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ VIR_FREE(event->data.blockJob.path);
+ break;
}
VIR_FREE(event->dom.name);
@@ -874,6 +884,44 @@ virDomainEventPtr virDomainEventGraphicsNewFromObj(virDomainObjPtr
obj,
return ev;
}
+static virDomainEventPtr
+virDomainEventBlockJobNew(int id, const char *name, unsigned char *uuid,
+ const char *path, int type, int status)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
+ id, name, uuid);
+
+ if (ev) {
+ if (!(ev->data.blockJob.path = strdup(path))) {
+ virReportOOMError();
+ virDomainEventFree(ev);
+ return NULL;
+ }
+ ev->data.blockJob.type = type;
+ ev->data.blockJob.status = status;
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventBlockJobNewFromObj(virDomainObjPtr obj,
+ const char *path,
+ int type,
+ int status)
+{
+ return virDomainEventBlockJobNew(obj->def->id, obj->def->name,
+ obj->def->uuid, path, type, status);
+}
+
+virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
+ const char *path,
+ int type,
+ int status)
+{
+ return virDomainEventBlockJobNew(dom->id, dom->name, dom->uuid,
+ path, type, status);
+}
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
@@ -1027,6 +1075,14 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ ((virConnectDomainEventBlockJobCallback)cb)(conn, dom,
+ event->data.blockJob.path,
+ event->data.blockJob.type,
+ event->data.blockJob.status,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index f56408f..b06be16 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -169,7 +169,14 @@ virDomainEventPtr virDomainEventGraphicsNewFromObj(virDomainObjPtr
obj,
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom);
virDomainEventPtr virDomainEventControlErrorNewFromObj(virDomainObjPtr obj);
-
+virDomainEventPtr virDomainEventBlockJobNewFromObj(virDomainObjPtr obj,
+ const char *path,
+ int type,
+ int status);
+virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
+ const char *path,
+ int type,
+ int status);
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3e3b1dd..c21119f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -403,6 +403,8 @@ virDomainWatchdogModelTypeToString;
# domain_event.h
+virDomainEventBlockJobNewFromObj;
+virDomainEventBlockJobNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
virDomainEventCallbackListCount;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5c048eb..e5ab9f3 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -957,6 +957,19 @@ int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
+ const char *diskAlias,
+ int type,
+ int status)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainBlockJob, mon->vm,
+ diskAlias, type, status);
+ return ret;
+}
+
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c5d27ef..73be07d 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -117,6 +117,11 @@ struct _qemuMonitorCallbacks {
const char *authScheme,
const char *x509dname,
const char *saslUsername);
+ int (*domainBlockJob)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *diskAlias,
+ int type,
+ int status);
};
@@ -179,6 +184,11 @@ int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
const char *authScheme,
const char *x509dname,
const char *saslUsername);
+int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
+ const char *diskAlias,
+ int type,
+ int status);
+
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e7163bb..2b18cd4 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -56,6 +56,7 @@ static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon,
virJSONValuePtr dat
static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr
data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr
data);
+static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data);
struct {
const char *type;
@@ -71,6 +72,7 @@ struct {
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
+ { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJob, },
};
@@ -678,6 +680,44 @@ static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon,
virJSONValueP
qemuMonitorJSONHandleVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
}
+static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data)
+{
+ const char *device;
+ const char *type_str;
+ int type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+ unsigned long long offset, len;
+ int status = VIR_DOMAIN_BLOCK_JOB_FAILED;
+
+ if ((device = virJSONValueObjectGetString(data, "device")) == NULL) {
+ VIR_WARN("missing device in block job event");
+ goto out;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "offset", &offset) < 0)
{
+ VIR_WARN("missing offset in block job event");
+ goto out;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "len", &len) < 0) {
+ VIR_WARN("missing len in block job event");
+ goto out;
+ }
+
+ if ((type_str = virJSONValueObjectGetString(data, "type")) == NULL) {
+ VIR_WARN("missing type in block job event");
+ goto out;
+ }
+
+ if (STREQ(type_str, "stream"))
+ type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
+
+ if (offset != 0 && offset == len)
+ status = VIR_DOMAIN_BLOCK_JOB_COMPLETED;
+
+out:
+ qemuMonitorEmitBlockJob(mon, device, type, status);
+}
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 448b06e..1a76d52 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -661,6 +661,36 @@ qemuProcessHandleIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
return 0;
}
+static int
+qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *diskAlias,
+ int type,
+ int status)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+ const char *path;
+ virDomainDiskDefPtr disk;
+
+ virDomainObjLock(vm);
+ disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias);
+
+ if (disk) {
+ path = disk->src;
+ event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
+ }
+
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
static int
qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
@@ -778,6 +808,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainWatchdog = qemuProcessHandleWatchdog,
.domainIOError = qemuProcessHandleIOError,
.domainGraphics = qemuProcessHandleGraphics,
+ .domainBlockJob = qemuProcessHandleBlockJob,
};
static int
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index a70b455..c627644 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -223,6 +223,11 @@ remoteDomainBuildEventControlError(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
remoteDomainBuildEventRTCChange,
@@ -256,6 +261,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventControlError,
sizeof(remote_domain_event_control_error_msg),
(xdrproc_t)xdr_remote_domain_event_control_error_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
+ remoteDomainBuildEventBlockJob,
+ sizeof(remote_domain_event_block_job_msg),
+ (xdrproc_t)xdr_remote_domain_event_block_job_msg },
};
enum virDrvOpenRemoteFlags {
@@ -3093,6 +3102,28 @@ remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED
remoteDomainEventQueue(priv, event);
}
+static void
+remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_block_job_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventBlockJobNewFromDom(dom, msg->path, msg->type,
+ msg->status);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
static void
remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 96113d8..6d6dff3 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -1934,6 +1934,13 @@ struct remote_domain_event_graphics_msg {
remote_domain_event_graphics_identity
subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
+struct remote_domain_event_block_job_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string path;
+ int type;
+ int status;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@@ -2422,7 +2429,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_JOB_ABORT = 231, /* autogen autogen */
REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO = 232, /* skipgen skipgen */
REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 233, /* autogen autogen */
- REMOTE_PROC_DOMAIN_BLOCK_PULL = 234 /* autogen autogen */
+ REMOTE_PROC_DOMAIN_BLOCK_PULL = 234, /* autogen autogen */
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 235 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index d6bcdd0..ab9b190 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1448,6 +1448,12 @@ struct remote_domain_event_graphics_msg {
remote_domain_event_graphics_identity * subject_val;
} subject;
};
+struct remote_domain_event_block_job_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string path;
+ int type;
+ int status;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -1892,5 +1898,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO = 232,
REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 233,
REMOTE_PROC_DOMAIN_BLOCK_PULL = 234,
-
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 235,
};
--
1.7.3