ping On 19.04.2018 17:18, Nikolay Shirokovskiy wrote: > If block job is completed with error qemu additionally > provides error message. This patch introduces new event > VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR to pass error message to client. > > This error message has no semantics and should not be interpreted. > API and RPC layer also have reserved 'code' field to pass semantics > loaded error code value in the future. > > Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@xxxxxxxxxxxxx> > > --- > > Diff from v1 [1]: > - replace block job event version 3 with block job error event > - add code field to API/RPC to pass error code in the future > > Peter, I decided not to use enum/union as this looks like to much effort to extend > code generation for this simple case. Using typed params looks unsuitable too. > > [1] https://www.redhat.com/archives/libvir-list/2017-October/msg01369.html > > examples/object-events/event-test.c | 20 ++++++++ > include/libvirt/libvirt-domain.h | 25 ++++++++++ > src/conf/domain_event.c | 92 +++++++++++++++++++++++++++++++++++++ > src/conf/domain_event.h | 13 ++++++ > src/libvirt_private.syms | 2 + > src/qemu/qemu_blockjob.c | 10 +++- > src/qemu/qemu_blockjob.h | 3 +- > src/qemu/qemu_domain.c | 4 +- > src/qemu/qemu_domain.h | 1 + > src/qemu/qemu_driver.c | 9 ++-- > src/qemu/qemu_process.c | 1 + > src/remote/remote_daemon_dispatch.c | 48 +++++++++++++++++++ > src/remote/remote_driver.c | 34 ++++++++++++++ > src/remote/remote_protocol.x | 17 ++++++- > src/remote_protocol-structs | 9 ++++ > tools/virsh-domain.c | 24 ++++++++++ > 16 files changed, 304 insertions(+), 8 deletions(-) > > diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c > index 8499e0b..23d5a3f 100644 > --- a/examples/object-events/event-test.c > +++ b/examples/object-events/event-test.c > @@ -936,6 +936,25 @@ myDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSED, > > > static int > +myDomainEventBlockJobErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED, > + virDomainPtr dom, > + const char *dev, > + int type, > + unsigned int code, > + const char *message, > + void *opaque) > +{ > + const char *eventName = opaque; > + > + printf("%s EVENT: Domain %s(%d) block job error callback '%s' disk '%s', " > + "type '%s' code '%u' message '%s'", > + __func__, virDomainGetName(dom), virDomainGetID(dom), eventName, > + dev, blockJobTypeToStr(type), code, NULLSTR(message)); > + return 0; > +} > + > + > +static int > myDomainEventBlockThresholdCallback(virConnectPtr conn ATTRIBUTE_UNUSED, > virDomainPtr dom, > const char *dev, > @@ -1082,6 +1101,7 @@ struct domainEventData domainEvents[] = { > DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback), > DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback), > DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback), > + DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR, myDomainEventBlockJobErrorCallback), > }; > > struct storagePoolEventData { > diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h > index 12fd340..ee55ab9 100644 > --- a/include/libvirt/libvirt-domain.h > +++ b/include/libvirt/libvirt-domain.h > @@ -4370,6 +4370,30 @@ typedef void (*virConnectDomainEventBlockThresholdCallback)(virConnectPtr conn, > unsigned long long excess, > void *opaque); > > + > +/** > + * virConnectDomainEventBlockJobErrorCallback: > + * @conn: connection object > + * @dom: domain on which the event occurred > + * @dev: name associated with the affected disk or storage backing chain > + * element > + * @type: type of block job (virDomainBlockJobType) > + * @code: always 0, reserved for future use > + * @message: error message with no semantics, can be NULL > + * @opaque: application specified data > + * > + * The callback occurs when block job is completed with error and provides > + * error message in @message. > + * > + */ > +typedef void (*virConnectDomainEventBlockJobErrorCallback)(virConnectPtr conn, > + virDomainPtr dom, > + const char *dev, > + int type, > + unsigned int code, > + const char *message, > + void *opaque); > + > /** > * VIR_DOMAIN_EVENT_CALLBACK: > * > @@ -4412,6 +4436,7 @@ typedef enum { > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED = 22, /* virConnectDomainEventDeviceRemovalFailedCallback */ > VIR_DOMAIN_EVENT_ID_METADATA_CHANGE = 23, /* virConnectDomainEventMetadataChangeCallback */ > VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD = 24, /* virConnectDomainEventBlockThresholdCallback */ > + VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR = 25, /* virConnectDomainEventBlockJobErrorCallback */ > > # ifdef VIR_ENUM_SENTINELS > VIR_DOMAIN_EVENT_ID_LAST > diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c > index 9752070..54f4cf4 100644 > --- a/src/conf/domain_event.c > +++ b/src/conf/domain_event.c > @@ -47,6 +47,7 @@ static virClassPtr virDomainEventWatchdogClass; > static virClassPtr virDomainEventIOErrorClass; > static virClassPtr virDomainEventGraphicsClass; > static virClassPtr virDomainEventBlockJobClass; > +static virClassPtr virDomainEventBlockJobErrorClass; > static virClassPtr virDomainEventDiskChangeClass; > static virClassPtr virDomainEventTrayChangeClass; > static virClassPtr virDomainEventBalloonChangeClass; > @@ -69,6 +70,7 @@ static void virDomainEventWatchdogDispose(void *obj); > static void virDomainEventIOErrorDispose(void *obj); > static void virDomainEventGraphicsDispose(void *obj); > static void virDomainEventBlockJobDispose(void *obj); > +static void virDomainEventBlockJobErrorDispose(void *obj); > static void virDomainEventDiskChangeDispose(void *obj); > static void virDomainEventTrayChangeDispose(void *obj); > static void virDomainEventBalloonChangeDispose(void *obj); > @@ -151,6 +153,17 @@ struct _virDomainEventBlockJob { > typedef struct _virDomainEventBlockJob virDomainEventBlockJob; > typedef virDomainEventBlockJob *virDomainEventBlockJobPtr; > > +struct _virDomainEventBlockJobError { > + virDomainEvent parent; > + > + char *dev; > + int type; > + unsigned int code; > + char *message; > +}; > +typedef struct _virDomainEventBlockJobError virDomainEventBlockJobError; > +typedef virDomainEventBlockJobError *virDomainEventBlockJobErrorPtr; > + > struct _virDomainEventGraphics { > virDomainEvent parent; > > @@ -309,6 +322,8 @@ virDomainEventsOnceInit(void) > return -1; > if (!VIR_CLASS_NEW(virDomainEventBlockJob, virDomainEventClass)) > return -1; > + if (!VIR_CLASS_NEW(virDomainEventBlockJobError, virDomainEventClass)) > + return -1; > if (!VIR_CLASS_NEW(virDomainEventDiskChange, virDomainEventClass)) > return -1; > if (!VIR_CLASS_NEW(virDomainEventTrayChange, virDomainEventClass)) > @@ -420,6 +435,16 @@ virDomainEventBlockJobDispose(void *obj) > } > > static void > +virDomainEventBlockJobErrorDispose(void *obj) > +{ > + virDomainEventBlockJobErrorPtr event = obj; > + VIR_DEBUG("obj=%p", event); > + > + VIR_FREE(event->dev); > + VIR_FREE(event->message); > +} > + > +static void > virDomainEventDiskChangeDispose(void *obj) > { > virDomainEventDiskChangePtr event = obj; > @@ -977,6 +1002,59 @@ virDomainEventBlockJob2NewFromDom(virDomainPtr dom, > dst, type, status); > } > > +static virObjectEventPtr > +virDomainEventBlockJobErrorNew(int id, > + const char *name, > + unsigned char *uuid, > + const char *dev, > + int type, > + unsigned int code, > + const char *message) > +{ > + virDomainEventBlockJobErrorPtr ev; > + > + if (virDomainEventsInitialize() < 0) > + return NULL; > + > + if (!(ev = virDomainEventNew(virDomainEventBlockJobErrorClass, > + VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR, > + id, name, uuid))) > + return NULL; > + > + if (VIR_STRDUP(ev->dev, dev) < 0) { > + virObjectUnref(ev); > + return NULL; > + } > + ignore_value(VIR_STRDUP_QUIET(ev->message, message)); > + ev->type = type; > + ev->code = code; > + > + return (virObjectEventPtr)ev; > +} > + > +virObjectEventPtr > +virDomainEventBlockJobErrorNewFromObj(virDomainObjPtr obj, > + const char *dev, > + int type, > + unsigned int code, > + const char *message) > +{ > + return virDomainEventBlockJobErrorNew(obj->def->id, obj->def->name, > + obj->def->uuid, dev, type, code, > + message); > +} > + > +virObjectEventPtr > +virDomainEventBlockJobErrorNewFromDom(virDomainPtr dom, > + const char *dev, > + int type, > + unsigned int code, > + const char *message) > +{ > + return virDomainEventBlockJobErrorNew(dom->id, dom->name, dom->uuid, > + dev, type, code, message); > +} > + > virObjectEventPtr > virDomainEventControlErrorNewFromDom(virDomainPtr dom) > { > @@ -1787,6 +1865,20 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, > goto cleanup; > } > > + case VIR_DOMAIN_EVENT_ID_BLOCK_JOB_ERROR: > + { > + virDomainEventBlockJobErrorPtr blockJobErrorEvent; > + > + blockJobErrorEvent = (virDomainEventBlockJobErrorPtr)event; > + ((virConnectDomainEventBlockJobErrorCallback)cb)(conn, dom, > + blockJobErrorEvent->dev, > + blockJobErrorEvent->type, > + blockJobErrorEvent->code, > + blockJobErrorEvent->message, > + cbopaque); > + goto cleanup; > + } > + > case VIR_DOMAIN_EVENT_ID_DISK_CHANGE: > { > virDomainEventDiskChangePtr diskChangeEvent; > diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h > index 3992a29..456026c 100644 > --- a/src/conf/domain_event.h > +++ b/src/conf/domain_event.h > @@ -138,6 +138,19 @@ virDomainEventBlockJob2NewFromDom(virDomainPtr dom, > int status); > > virObjectEventPtr > +virDomainEventBlockJobErrorNewFromObj(virDomainObjPtr obj, > + const char *dev, > + int type, > + unsigned int code, > + const char *message); > +virObjectEventPtr > +virDomainEventBlockJobErrorNewFromDom(virDomainPtr dom, > + const char *dev, > + int type, > + unsigned int code, > + const char *message); > + > +virObjectEventPtr > virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj, > const char *oldSrcPath, > const char *newSrcPath, > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index b31f599..303f28c 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -589,6 +589,8 @@ virDomainEventBalloonChangeNewFromDom; > virDomainEventBalloonChangeNewFromObj; > virDomainEventBlockJob2NewFromDom; > virDomainEventBlockJob2NewFromObj; > +virDomainEventBlockJobErrorNewFromDom; > +virDomainEventBlockJobErrorNewFromObj; > virDomainEventBlockJobNewFromDom; > virDomainEventBlockJobNewFromObj; > virDomainEventBlockThresholdNewFromDom; > diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c > index 617e4ee..4df4ed6 100644 > --- a/src/qemu/qemu_blockjob.c > +++ b/src/qemu/qemu_blockjob.c > @@ -70,7 +70,8 @@ qemuBlockJobUpdate(virQEMUDriverPtr driver, > if (status != -1) { > qemuBlockJobEventProcess(driver, vm, disk, asyncJob, > diskPriv->blockJobType, > - diskPriv->blockJobStatus); > + diskPriv->blockJobStatus, > + diskPriv->blockJobError); > diskPriv->blockJobStatus = -1; > if (error) > VIR_STEAL_PTR(*error, diskPriv->blockJobError); > @@ -100,10 +101,12 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, > virDomainDiskDefPtr disk, > qemuDomainAsyncJob asyncJob, > int type, > - int status) > + int status, > + const char *error) > { > virObjectEventPtr event = NULL; > virObjectEventPtr event2 = NULL; > + virObjectEventPtr errorEvent = NULL; > const char *path; > virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); > virDomainDiskDefPtr persistDisk = NULL; > @@ -123,6 +126,8 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, > path = virDomainDiskGetSource(disk); > event = virDomainEventBlockJobNewFromObj(vm, path, type, status); > event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status); > + if (error) > + errorEvent = virDomainEventBlockJobErrorNewFromObj(vm, disk->dst, type, 0, error); > > /* If we completed a block pull or commit, then update the XML > * to match. */ > @@ -213,6 +218,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, > > qemuDomainEventQueue(driver, event); > qemuDomainEventQueue(driver, event2); > + qemuDomainEventQueue(driver, errorEvent); > > virObjectUnref(cfg); > } > diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h > index e71d691..18bcaaa 100644 > --- a/src/qemu/qemu_blockjob.h > +++ b/src/qemu/qemu_blockjob.h > @@ -36,7 +36,8 @@ void qemuBlockJobEventProcess(virQEMUDriverPtr driver, > virDomainDiskDefPtr disk, > qemuDomainAsyncJob asyncJob, > int type, > - int status); > + int status, > + const char *error); > > void qemuBlockJobSyncBegin(virDomainDiskDefPtr disk); > void qemuBlockJobSyncEnd(virQEMUDriverPtr driver, > diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c > index e2a8450..883652d 100644 > --- a/src/qemu/qemu_domain.c > +++ b/src/qemu/qemu_domain.c > @@ -11951,12 +11951,14 @@ qemuProcessEventFree(struct qemuProcessEvent *event) > case QEMU_PROCESS_EVENT_GUESTPANIC: > qemuMonitorEventPanicInfoFree(event->data); > break; > + case QEMU_PROCESS_EVENT_MONITOR_EOF: > + VIR_FREE(event->error); > + ATTRIBUTE_FALLTHROUGH; > case QEMU_PROCESS_EVENT_WATCHDOG: > case QEMU_PROCESS_EVENT_DEVICE_DELETED: > case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED: > case QEMU_PROCESS_EVENT_SERIAL_CHANGED: > case QEMU_PROCESS_EVENT_BLOCK_JOB: > - case QEMU_PROCESS_EVENT_MONITOR_EOF: > VIR_FREE(event->data); > break; > case QEMU_PROCESS_EVENT_LAST: > diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h > index 2c27dfb..f3b262f 100644 > --- a/src/qemu/qemu_domain.h > +++ b/src/qemu/qemu_domain.h > @@ -456,6 +456,7 @@ struct qemuProcessEvent { > int action; > int status; > void *data; > + char *error; > }; > > void qemuProcessEventFree(struct qemuProcessEvent *event); > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c > index 5673d9f..cefbe52 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -4748,7 +4748,8 @@ processBlockJobEvent(virQEMUDriverPtr driver, > virDomainObjPtr vm, > const char *diskAlias, > int type, > - int status) > + int status, > + char *error) > { > virDomainDiskDefPtr disk; > > @@ -4761,7 +4762,8 @@ processBlockJobEvent(virQEMUDriverPtr driver, > } > > if ((disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias))) > - qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE, type, status); > + qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE, > + type, status, error); > > endjob: > qemuDomainObjEndJob(driver, vm); > @@ -4846,7 +4848,8 @@ static void qemuProcessEventHandler(void *data, void *opaque) > processBlockJobEvent(driver, vm, > processEvent->data, > processEvent->action, > - processEvent->status); > + processEvent->status, > + processEvent->error); > break; > case QEMU_PROCESS_EVENT_MONITOR_EOF: > processMonitorEOFEvent(driver, vm); > diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c > index 6a5262a..12b156f 100644 > --- a/src/qemu/qemu_process.c > +++ b/src/qemu/qemu_process.c > @@ -1026,6 +1026,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED, > processEvent->vm = virObjectRef(vm); > processEvent->action = type; > processEvent->status = status; > + ignore_value(VIR_STRDUP_QUIET(processEvent->error, error)); > > if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) { > ignore_value(virObjectUnref(vm)); > diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c > index a8a5932..07c9dbb 100644 > --- a/src/remote/remote_daemon_dispatch.c > +++ b/src/remote/remote_daemon_dispatch.c > @@ -1342,6 +1342,53 @@ remoteRelayDomainEventBlockThreshold(virConnectPtr conn, > } > > > +static int > +remoteRelayDomainEventBlockJobError(virConnectPtr conn, > + virDomainPtr dom, > + const char *dev, > + int type, > + unsigned int code, > + const char *message, > + void *opaque) > +{ > + daemonClientEventCallbackPtr callback = opaque; > + remote_domain_event_block_job_error_msg msg; > + > + if (callback->callbackID < 0 || > + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) > + return -1; > + > + VIR_DEBUG("Relaying domain block job error event %s %d %s %i %u %s, callback %d", > + dom->name, dom->id, dev, type, code, NULLSTR(message), > + callback->callbackID); > + > + memset(&msg, 0, sizeof(msg)); > + msg.callbackID = callback->callbackID; > + if (VIR_STRDUP(msg.dev, dev) < 0) > + return -1; > + if (message) { > + if (VIR_ALLOC(msg.message) < 0 || > + VIR_STRDUP(*(msg.message), message) < 0) > + goto error; > + } > + msg.type = type; > + msg.code = code; > + make_nonnull_domain(&msg.dom, dom); > + > + remoteDispatchObjectEventSend(callback->client, remoteProgram, > + REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR, > + (xdrproc_t)xdr_remote_domain_event_block_job_error_msg, > + &msg); > + return 0; > + > + error: > + VIR_FREE(msg.dev); > + VIR_FREE(msg.message); > + > + return -1; > +} > + > + > static virConnectDomainEventGenericCallback domainEventCallbacks[] = { > VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), > VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), > @@ -1368,6 +1415,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { > VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed), > VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange), > VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold), > + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJobError), > }; > > verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); > diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c > index d3b588c..0d30bf3 100644 > --- a/src/remote/remote_driver.c > +++ b/src/remote/remote_driver.c > @@ -405,6 +405,11 @@ remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_U > virNetClientPtr client ATTRIBUTE_UNUSED, > void *evdata, void *opaque); > > +static void > +remoteDomainBuildEventBlockJobError(virNetClientProgramPtr prog, > + virNetClientPtr client, > + void *evdata, void *opaque); > + > static virNetClientProgramEvent remoteEvents[] = { > { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE, > remoteDomainBuildEventLifecycle, > @@ -611,6 +616,10 @@ static virNetClientProgramEvent remoteEvents[] = { > remoteDomainBuildEventBlockThreshold, > sizeof(remote_domain_event_block_threshold_msg), > (xdrproc_t)xdr_remote_domain_event_block_threshold_msg }, > + { REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR, > + remoteDomainBuildEventBlockJobError, > + sizeof(remote_domain_event_block_job_error_msg), > + (xdrproc_t)xdr_remote_domain_event_block_job_error_msg }, > }; > > static void > @@ -5533,6 +5542,31 @@ remoteDomainBuildEventBlockThreshold(virNetClientProgramPtr prog ATTRIBUTE_UNUSE > } > > > +static void > +remoteDomainBuildEventBlockJobError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, > + virNetClientPtr client ATTRIBUTE_UNUSED, > + void *evdata, void *opaque) > +{ > + virConnectPtr conn = opaque; > + remote_domain_event_block_job_error_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 = virDomainEventBlockJobErrorNewFromDom(dom, msg->dev, msg->type, > + msg->code, > + msg->message ? *msg->message : NULL); > + > + virObjectUnref(dom); > + > + remoteEventQueue(priv, event, msg->callbackID); > +} > + > + > static int > remoteStreamSend(virStreamPtr st, > const char *data, > diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x > index 296a087..051a773 100644 > --- a/src/remote/remote_protocol.x > +++ b/src/remote/remote_protocol.x > @@ -3103,6 +3103,15 @@ struct remote_domain_event_block_job_2_msg { > int status; > }; > > +struct remote_domain_event_block_job_error_msg { > + int callbackID; > + remote_nonnull_domain dom; > + remote_nonnull_string dev; > + int type; > + int code; > + remote_string message; > +}; > + > struct remote_domain_event_block_threshold_msg { > int callbackID; > remote_nonnull_domain dom; > @@ -6135,5 +6144,11 @@ enum remote_procedure { > * @priority: high > * @acl: storage_pool:getattr > */ > - REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391 > + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391, > + > + /** > + * @generate: none > + * @acl: none > + */ > + REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR = 392 > }; > diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs > index fe163db..567f307 100644 > --- a/src/remote_protocol-structs > +++ b/src/remote_protocol-structs > @@ -2541,6 +2541,14 @@ struct remote_domain_event_block_job_2_msg { > int type; > int status; > }; > +struct remote_domain_event_block_job_error_msg { > + int callbackID; > + remote_nonnull_domain dom; > + remote_nonnull_string dev; > + int type; > + int code; > + remote_string message; > +}; > struct remote_domain_event_block_threshold_msg { > int callbackID; > remote_nonnull_domain dom; > @@ -3269,4 +3277,5 @@ enum remote_procedure { > REMOTE_PROC_DOMAIN_MANAGED_SAVE_DEFINE_XML = 389, > REMOTE_PROC_DOMAIN_SET_LIFECYCLE_ACTION = 390, > REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391, > + REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_ERROR = 392, > }; > diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c > index 2b775fc..40d3c82 100644 > --- a/tools/virsh-domain.c > +++ b/tools/virsh-domain.c > @@ -13286,6 +13286,28 @@ virshEventBlockThresholdPrint(virConnectPtr conn ATTRIBUTE_UNUSED, > } > > > +static void > +virshEventBlockJobErrorPrint(virConnectPtr conn ATTRIBUTE_UNUSED, > + virDomainPtr dom, > + const char *dev, > + int type, > + unsigned int code ATTRIBUTE_UNUSED, > + const char *message, > + void *opaque) > +{ > + virBuffer buf = VIR_BUFFER_INITIALIZER; > + > + virBufferAsprintf(&buf, _("event '%s' for domain %s: %s for %s, " > + "error: %s\n"), > + ((virshDomEventData *) opaque)->cb->name, > + virDomainGetName(dom), > + virshDomainBlockJobToString(type), > + dev, > + NULLSTR(message)); > + virshEventPrint(opaque, &buf); > +} > + > + > static vshEventCallback vshEventCallbacks[] = { > { "lifecycle", > VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), }, > @@ -13335,6 +13357,8 @@ static vshEventCallback vshEventCallbacks[] = { > VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), }, > { "block-threshold", > VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), }, > + { "block-job-error", > + VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockJobErrorPrint), }, > }; > verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks)); > > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list