return 0;
}
+static int remoteRelayDomainEventBlockPull(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *path,
+ int status,
+ void *opaque)
+{
+ struct qemud_client *client = opaque;
+ remote_domain_event_block_pull_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain block pull event %s %d %s %i", dom->name, dom->id, path, status);
+
+ virMutexLock(&client->lock);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ make_nonnull_domain(&data.dom, dom);
+ data.path = (char*)path;
+ data.status = status;
+
+ remoteDispatchDomainEventSend(client,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_PULL,
+ (xdrproc_t)xdr_remote_domain_event_block_pull_msg, &data);
+
+ virMutexUnlock(&client->lock);
+
+ return 0;
+}
+
static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockPull),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
+/**
+ * virConnectDomainEventBlockPullStatus:
+ *
+ * The final status of a virDomainBlockPullAll() operation
+ */
+typedef enum {
+ VIR_DOMAIN_BLOCK_PULL_COMPLETED = 0,
+ VIR_DOMAIN_BLOCK_PULL_FAILED = 1,
+} virConnectDomainEventBlockPullStatus;
+
+/**
+ * virConnectDomainEventBlockPullCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @path: fully-qualified filename of the affected disk
+ * @status: final status of the operation (virConnectDomainEventBlockPullStatus)
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_BLOCK_PULL with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventBlockPullCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *path,
+ int status,
+ void *opaque);
+
/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
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_PULL = 8, /* virConnectDomainEventBlockPullCallback */
/*
* NB: this enum value will increase over time as new events are
except AttributeError:
pass
+ def dispatchDomainEventBlockPullCallback(self, dom, path, status, cbData):
+ """Dispatches events to python user domain blockPull event callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), path, 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 """
return ret;
}
+static int
+libvirt_virConnectDomainEventBlockPullCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *path,
+ 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*)"OsiO",
+ pyobj_dom, path, 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)
case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventGenericCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_BLOCK_PULL:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBlockPullCallback);
+ break;
}
if (!cb) {
char *authScheme;
virDomainEventGraphicsSubjectPtr subject;
} graphics;
+ struct {
+ char *path;
+ int status;
+ } blockPull;
} data;
};
}
VIR_FREE(event->data.graphics.subject);
}
+ break;
+
+ case VIR_DOMAIN_EVENT_ID_BLOCK_PULL:
+ VIR_FREE(event->data.blockPull.path);
+ break;
}
VIR_FREE(event->dom.name);
return ev;
}
+static virDomainEventPtr
+virDomainEventBlockPullNew(int id, const char *name, unsigned char *uuid,
+ const char *path, int status)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_BLOCK_PULL,
+ id, name, uuid);
+
+ if (ev) {
+ if (!(ev->data.blockPull.path = strdup(path))) {
+ virReportOOMError();
+ virDomainEventFree(ev);
+ return NULL;
+ }
+ ev->data.blockPull.status = status;
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventBlockPullNewFromObj(virDomainObjPtr obj,
+ const char *path,
+ int status)
+{
+ return virDomainEventBlockPullNew(obj->def->id, obj->def->name,
+ obj->def->uuid, path, status);
+}
+
+virDomainEventPtr virDomainEventBlockPullNewFromDom(virDomainPtr dom,
+ const char *path,
+ int status)
+{
+ return virDomainEventBlockPullNew(dom->id, dom->name, dom->uuid,
+ path, status);
+}
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
cbopaque);
break;
+ case VIR_DOMAIN_EVENT_ID_BLOCK_PULL:
+ ((virConnectDomainEventBlockPullCallback)cb)(conn, dom,
+ event->data.blockPull.path,
+ event->data.blockPull.status,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom);
virDomainEventPtr virDomainEventControlErrorNewFromObj(virDomainObjPtr obj);
-
+virDomainEventPtr virDomainEventBlockPullNewFromObj(virDomainObjPtr obj,
+ const char *path,
+ int status);
+virDomainEventPtr virDomainEventBlockPullNewFromDom(virDomainPtr dom,
+ const char *path,
+ int status);
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
# domain_event.h
+virDomainEventBlockPullNewFromObj;
+virDomainEventBlockPullNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
virDomainEventCallbackListCount;
return ret;
}
+int qemuMonitorEmitBlockPull(qemuMonitorPtr mon,
+ const char *diskAlias,
+ int status)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainBlockPull, mon->vm,
+ diskAlias, status);
+ return ret;
+}
+
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
const char *authScheme,
const char *x509dname,
const char *saslUsername);
+ int (*domainBlockPull)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *diskAlias,
+ int status);
};
const char *authScheme,
const char *x509dname,
const char *saslUsername);
+int qemuMonitorEmitBlockPull(qemuMonitorPtr mon,
+ const char *diskAlias,
+ int status);
+
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleBlockPull(qemuMonitorPtr mon, virJSONValuePtr data);
struct {
const char *type;
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
+ { "BLOCK_STREAM_COMPLETED", qemuMonitorJSONHandleBlockPull, },
};
qemuMonitorJSONHandleVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
}
+static void qemuMonitorJSONHandleBlockPull(qemuMonitorPtr mon, virJSONValuePtr data)
+{
+ const char *device;
+ unsigned long long offset, len;
+ int status = VIR_DOMAIN_BLOCK_PULL_FAILED;
+
+ if ((device = virJSONValueObjectGetString(data, "device")) == NULL) {
+ VIR_WARN("missing device in disk io error event");
+ goto out;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "offset", &offset) < 0) {
+ VIR_WARN("missing offset in block pull event");
+ goto out;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "len", &len) < 0) {
+ VIR_WARN("missing len in block pull event");
+ goto out;
+ }
+
+ if (offset != 0 && offset == len)
+ status = VIR_DOMAIN_BLOCK_PULL_COMPLETED;
+
+out:
+ qemuMonitorEmitBlockPull(mon, device, status);
+}
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
return 0;
}
+static int
+qemuProcessHandleBlockPull(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *diskAlias,
+ 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 = virDomainEventBlockPullNewFromObj(vm, path, status);
+ }
+
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
static int
qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
.domainWatchdog = qemuProcessHandleWatchdog,
.domainIOError = qemuProcessHandleIOError,
.domainGraphics = qemuProcessHandleGraphics,
+ .domainBlockPull = qemuProcessHandleBlockPull,
};
static int
return event;
}
+static virDomainEventPtr
+remoteDomainReadEventBlockPull(virConnectPtr conn, XDR *xdr)
+{
+ remote_domain_event_block_pull_msg msg;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+ memset (&msg, 0, sizeof msg);
+
+ /* unmarshall parameters, and process it*/
+ if (! xdr_remote_domain_event_block_pull_msg(xdr, &msg) ) {
+ remoteError(VIR_ERR_RPC, "%s",
+ _("unable to demarshall block_pull event"));
+ return NULL;
+ }
+
+ dom = get_nonnull_domain(conn,msg.dom);
+ if (!dom)
+ return NULL;
+
+ event = virDomainEventBlockPullNewFromDom(dom, msg.path, msg.status);
+ xdr_free ((xdrproc_t) &xdr_remote_domain_event_block_pull_msg, (char *) &msg);
+
+ virDomainFree(dom);
+ return event;
+}
+
static virDomainEventPtr
remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
event = remoteDomainReadEventControlError(conn, xdr);
break;
+ case REMOTE_PROC_DOMAIN_EVENT_BLOCK_PULL:
+ event = remoteDomainReadEventBlockPull(conn, xdr);
+ break;
+
default:
VIR_DEBUG("Unexpected event proc %d", hdr->proc);
break;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
+struct remote_domain_event_block_pull_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string path;
+ int status;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
REMOTE_PROC_DOMAIN_BLOCK_PULL_ALL = 230, /* autogen autogen */
REMOTE_PROC_DOMAIN_BLOCK_PULL_ABORT = 231, /* autogen autogen */
- REMOTE_PROC_DOMAIN_GET_BLOCK_PULL_INFO = 232 /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_GET_BLOCK_PULL_INFO = 232, /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_PULL = 233 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
remote_domain_event_graphics_identity * subject_val;
} subject;
};
+struct remote_domain_event_block_pull_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string path;
+ int status;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;