}
+static int
+remoteRelayDomainEventBlockJob2(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *dst,
+ int type,
+ int status,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_block_job_2_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain block job 2 event %s %d %s %i, %i, callback %d",
+ dom->name, dom->id, dst, type, status, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ if (VIR_STRDUP(data.dst, dst) < 0)
+ goto error;
+ data.type = type;
+ data.status = status;
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2,
+ (xdrproc_t)xdr_remote_domain_event_block_job_2_msg, &data);
+
+ return 0;
+ error:
+ VIR_FREE(data.dst);
+ return -1;
+}
+
+
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
* virConnectDomainEventBlockJobCallback:
* @conn: connection object
* @dom: domain on which the event occurred
- * @disk: fully-qualified filename of the affected disk
+ * @disk: name associated with the affected disk (filename or target
+ * device, depending on how the callback was registered)
* @type: type of block job (virDomainBlockJobType)
* @status: status of the operation (virConnectDomainEventBlockJobStatus)
* @opaque: application specified data
*
- * The callback signature to use when registering for an event of type
- * VIR_DOMAIN_EVENT_ID_BLOCK_JOB with virConnectDomainEventRegisterAny()
+ * The string returned for @disk can be used in any of the libvirt API
+ * that operate on a particular disk of the domain, and depends on what
+ * event type was registered with virConnectDomainEventRegisterAny().
+ * If the callback was registered using the older type of
+ * VIR_DOMAIN_EVENT_ID_BLOCK_JOB, then @disk contains the absolute file
+ * name of the host resource for the active layer of the disk; however,
+ * this name is unstable (pivoting via block copy or active block commit
+ * will change which file is active, giving a different name for the two
+ * events associated with the same job) and cannot be relied on if the
+ * active layer is associated with a network resource. If the callback
+ * was registered using the newer type of VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2,
+ * then @disk will contain the device target shorthand (the <target
+ * dev='...'/> sub-element, such as "vda").
*/
typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
virDomainPtr dom,
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE = 13, /* virConnectDomainEventBalloonChangeCallback */
VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK = 14, /* virConnectDomainEventPMSuspendDiskCallback */
VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED = 15, /* virConnectDomainEventDeviceRemovedCallback */
+ VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2 = 16, /* virConnectDomainEventBlockJobCallback */
#ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_ID_LAST
struct _virDomainEventBlockJob {
virDomainEvent parent;
- char *path;
+ char *disk; /* path or dst, depending on event id */
int type;
int status;
};
virDomainEventBlockJobPtr event = obj;
VIR_DEBUG("obj=%p", event);
- VIR_FREE(event->path);
+ VIR_FREE(event->disk);
}
static void
}
static virObjectEventPtr
-virDomainEventBlockJobNew(int id,
+virDomainEventBlockJobNew(int event,
+ int id,
const char *name,
unsigned char *uuid,
- const char *path,
+ const char *disk,
int type,
int status)
{
return NULL;
if (!(ev = virDomainEventNew(virDomainEventBlockJobClass,
- VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
+ event,
id, name, uuid)))
return NULL;
- if (VIR_STRDUP(ev->path, path) < 0) {
+ if (VIR_STRDUP(ev->disk, disk) < 0) {
virObjectUnref(ev);
return NULL;
}
int type,
int status)
{
- return virDomainEventBlockJobNew(obj->def->id, obj->def->name,
+ return virDomainEventBlockJobNew(VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
+ obj->def->id, obj->def->name,
obj->def->uuid, path, type, status);
}
int type,
int status)
{
- return virDomainEventBlockJobNew(dom->id, dom->name, dom->uuid,
+ return virDomainEventBlockJobNew(VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
+ dom->id, dom->name, dom->uuid,
path, type, status);
}
+virObjectEventPtr
+virDomainEventBlockJob2NewFromObj(virDomainObjPtr obj,
+ const char *dst,
+ int type,
+ int status)
+{
+ return virDomainEventBlockJobNew(VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2,
+ obj->def->id, obj->def->name,
+ obj->def->uuid, dst, type, status);
+}
+
+virObjectEventPtr
+virDomainEventBlockJob2NewFromDom(virDomainPtr dom,
+ const char *dst,
+ int type,
+ int status)
+{
+ return virDomainEventBlockJobNew(VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2,
+ dom->id, dom->name, dom->uuid,
+ dst, type, status);
+}
+
virObjectEventPtr
virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
goto cleanup;
case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2:
{
virDomainEventBlockJobPtr blockJobEvent;
blockJobEvent = (virDomainEventBlockJobPtr)event;
((virConnectDomainEventBlockJobCallback)cb)(conn, dom,
- blockJobEvent->path,
+ blockJobEvent->disk,
blockJobEvent->type,
blockJobEvent->status,
cbopaque);
int type,
int status);
+virObjectEventPtr
+virDomainEventBlockJob2NewFromObj(virDomainObjPtr obj,
+ const char *dst,
+ int type,
+ int status);
+virObjectEventPtr
+virDomainEventBlockJob2NewFromDom(virDomainPtr dom,
+ const char *dst,
+ int type,
+ int status);
+
virObjectEventPtr
virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj,
const char *oldSrcPath,
# conf/domain_event.h
virDomainEventBalloonChangeNewFromDom;
virDomainEventBalloonChangeNewFromObj;
+virDomainEventBlockJob2NewFromDom;
+virDomainEventBlockJob2NewFromObj;
virDomainEventBlockJobNewFromDom;
virDomainEventBlockJobNewFromObj;
virDomainEventControlErrorNewFromDom;
int ret = -1;
bool async = false;
virObjectEventPtr event = NULL;
+ virObjectEventPtr event2 = NULL;
int idx;
virDomainDiskDefPtr disk;
virStorageSourcePtr baseSource = NULL;
if (mode == BLOCK_JOB_ABORT) {
if (!async) {
/* Older qemu that lacked async reporting also lacked
- * active commit, so we can hardcode the event to pull */
+ * active commit, so we can hardcode the event to pull.
+ * We have to generate two variants of the event. */
int type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
int status = VIR_DOMAIN_BLOCK_JOB_CANCELED;
event = virDomainEventBlockJobNewFromObj(vm, disk->src->path, type,
status);
+ event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type,
+ status);
} else if (!(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC)) {
while (1) {
/* Poll every 50ms */
virObjectUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
+ if (event2)
+ qemuDomainEventQueue(driver, event2);
return ret;
}
{
virQEMUDriverPtr driver = opaque;
virObjectEventPtr event = NULL;
+ virObjectEventPtr event2 = NULL;
const char *path;
virDomainDiskDefPtr disk;
disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias);
if (disk) {
+ /* Have to generate two variants of the event for old vs. new
+ * client callbacks */
path = virDomainDiskGetSource(disk);
event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
+ event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type,
+ status);
/* XXX If we completed a block pull or commit, then recompute
* the cached backing chain to match. Better would be storing
* the chain ourselves rather than reprobing, but this
if (event)
qemuDomainEventQueue(driver, event);
+ if (event2)
+ qemuDomainEventQueue(driver, event2);
return 0;
}
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventBlockJob2(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
static void
remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
remoteDomainBuildEventCallbackDeviceRemoved,
sizeof(remote_domain_event_callback_device_removed_msg),
(xdrproc_t)xdr_remote_domain_event_callback_device_removed_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2,
+ remoteDomainBuildEventBlockJob2,
+ sizeof(remote_domain_event_block_job_2_msg),
+ (xdrproc_t)xdr_remote_domain_event_block_job_2_msg },
};
remote_domain_event_callback_block_job_msg *msg = evdata;
remoteDomainBuildEventBlockJobHelper(conn, &msg->msg, msg->callbackID);
}
+static void
+remoteDomainBuildEventBlockJob2(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ remote_domain_event_block_job_2_msg *msg = evdata;
+ struct private_data *priv = conn->privateData;
+ virDomainPtr dom;
+ virObjectEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventBlockJob2NewFromDom(dom, msg->dst, msg->type,
+ msg->status);
+
+ virDomainFree(dom);
+
+ remoteEventQueue(priv, event, msg->callbackID);
+}
static void
remoteDomainBuildEventGraphicsHelper(virConnectPtr conn,
remote_domain_event_device_removed_msg msg;
};
+struct remote_domain_event_block_job_2_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_nonnull_string dst;
+ int type;
+ int status;
+};
+
struct remote_connect_get_cpu_model_names_args {
remote_nonnull_string arch;
int need_results;
* @generate: both
* @acl: domain:set_time
*/
- REMOTE_PROC_DOMAIN_SET_TIME = 338
+ REMOTE_PROC_DOMAIN_SET_TIME = 338,
+
+ /**
+ * @generate: none
+ * @acl: none
+ */
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2 = 339
};
int callbackID;
remote_domain_event_device_removed_msg msg;
};
+struct remote_domain_event_block_job_2_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_nonnull_string dst;
+ int type;
+ int status;
+};
struct remote_connect_get_cpu_model_names_args {
remote_nonnull_string arch;
int need_results;
REMOTE_PROC_DOMAIN_FSTHAW = 336,
REMOTE_PROC_DOMAIN_GET_TIME = 337,
REMOTE_PROC_DOMAIN_SET_TIME = 338,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2 = 339,
};
if (!data->loop && *data->count)
return;
- vshPrint(data->ctl, _("event 'block-job' for domain %s: %s for %s %s\n"),
- virDomainGetName(dom), vshDomainBlockJobToString(type),
+ vshPrint(data->ctl, _("event '%s' for domain %s: %s for %s %s\n"),
+ data->cb->name, virDomainGetName(dom),
+ vshDomainBlockJobToString(type),
disk, vshDomainBlockJobStatusToString(status));
(*data->count)++;
if (!data->loop)
VIR_DOMAIN_EVENT_CALLBACK(vshEventPMChangePrint), },
{ "device-removed",
VIR_DOMAIN_EVENT_CALLBACK(vshEventDeviceRemovedPrint), },
+ { "block-job-2",
+ VIR_DOMAIN_EVENT_CALLBACK(vshEventBlockJobPrint), },
};
verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));