This introduces a new event type VIR_DOMAIN_EVENT_ID_IO_ERROR This event includes the action that is about to be taken as a result of the watchdog triggering typedef enum { VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0, VIR_DOMAIN_EVENT_IO_ERROR_PAUSE, VIR_DOMAIN_EVENT_IO_ERROR_REPORT, } virDomainEventIOErrorAction; In addition is has the source path of the disk that had the error and its unique device alias. It does not include the target device name (/dev/sda), since this would preclude triggering IO errors from other file backed devices (eg serial ports connected to a file) Thus there is a new callback definition for this event type typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn, virDomainPtr dom, const char *srcPath, const char *devAlias, int action, void *opaque); This is currently wired up to the QEMU block IO error events * daemon/remote.c: Dispatch IO error events to client * examples/domain-events/events-c/event-test.c: Watch for IO error events * include/libvirt/libvirt.h.in: Define new IO error event ID and callback signature * src/conf/domain_event.c, src/conf/domain_event.h, src/libvirt_private.syms: Extend API to handle IO error events * src/qemu/qemu_driver.c: Connect to the QEMU monitor event for block IO errors and emit a libvirt IO error event * src/remote/remote_driver.c: Receive and dispatch IO error events to application * src/remote/remote_protocol.x: Wire protocol definition for IO error events * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h, src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event from QEMU monitor --- daemon/remote.c | 35 +++++++++++++++ daemon/remote_dispatch_table.h | 5 ++ examples/domain-events/events-c/event-test.c | 23 ++++++++++- include/libvirt/libvirt.h.in | 12 +++++ src/conf/domain_event.c | 59 ++++++++++++++++++++++++++ src/conf/domain_event.h | 9 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 57 +++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 17 +++++++ src/qemu/qemu_monitor.h | 7 +++ src/qemu/qemu_monitor_json.c | 38 ++++++++++++++++- src/remote/remote_driver.c | 34 +++++++++++++++ src/remote/remote_protocol.c | 15 +++++++ src/remote/remote_protocol.h | 11 +++++ src/remote/remote_protocol.x | 10 ++++- 15 files changed, 330 insertions(+), 4 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index b1562b6..e2912a1 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -217,11 +217,46 @@ static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED, } +static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *srcPath, + const char *devAlias, + int action, + void *opaque) +{ + struct qemud_client *client = opaque; + remote_domain_event_io_error_msg data; + + if (!client) + return -1; + + REMOTE_DEBUG("Relaying domain io error %s %d %s %s %d", dom->name, dom->id, srcPath, devAlias, action); + + virMutexLock(&client->lock); + + /* build return data */ + memset(&data, 0, sizeof data); + make_nonnull_domain (&data.dom, dom); + data.srcPath = (char*)srcPath; + data.devAlias = (char*)devAlias; + data.action = action; + + remoteDispatchDomainEventSend (client, + REMOTE_PROC_DOMAIN_EVENT_IO_ERROR, + (xdrproc_t)xdr_remote_domain_event_io_error_msg, &data); + + virMutexUnlock(&client->lock); + + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventRTCChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError), }; verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index 11520b9..31d652d 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -852,3 +852,8 @@ .args_filter = (xdrproc_t) xdr_void, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* Async event DomainEventIoError => 170 */ + .fn = NULL, + .args_filter = (xdrproc_t) xdr_void, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c index 997af63..bb3c7bb 100644 --- a/examples/domain-events/events-c/event-test.c +++ b/examples/domain-events/events-c/event-test.c @@ -204,6 +204,19 @@ static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED, return 0; } +static int myDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *srcPath, + const char *devAlias, + int action, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n", __func__, virDomainGetName(dom), + virDomainGetID(dom), srcPath, devAlias, action); + + return 0; +} + static void myFreeFunc(void *opaque) { char *str = opaque; @@ -324,6 +337,7 @@ int main(int argc, char **argv) int callback3ret = -1; int callback4ret = -1; int callback5ret = -1; + int callback6ret = -1; struct sigaction action_stop = { .sa_handler = stop @@ -376,12 +390,18 @@ int main(int argc, char **argv) VIR_DOMAIN_EVENT_ID_WATCHDOG, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventWatchdogCallback), strdup("callback watchdog"), myFreeFunc); + callback6ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_IO_ERROR, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventIOErrorCallback), + strdup("callback io error"), myFreeFunc); if ((callback1ret != -1) && (callback2ret != -1) && (callback3ret != -1) && (callback4ret != -1) && - (callback5ret != -1)) { + (callback5ret != -1) && + (callback6ret != -1)) { while(run) { struct pollfd pfd = { .fd = h_fd, .events = h_event, @@ -422,6 +442,7 @@ int main(int argc, char **argv) virConnectDomainEventDeregisterAny(dconn, callback3ret); virConnectDomainEventDeregisterAny(dconn, callback4ret); virConnectDomainEventDeregisterAny(dconn, callback5ret); + virConnectDomainEventDeregisterAny(dconn, callback6ret); } DEBUG0("Closing connection"); diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 7bee89c..bffd9ed 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1858,6 +1858,17 @@ typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn, virDomainPtr dom, int action, void *opaque); +typedef enum { + VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0, + VIR_DOMAIN_EVENT_IO_ERROR_PAUSE, + VIR_DOMAIN_EVENT_IO_ERROR_REPORT, +} virDomainEventIOErrorAction; +typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *srcPath, + const char *devAlias, + int action, + void *opaque); /* Use this to cast the event specific callback into the generic one * for use for virDomainEventRegister */ @@ -1869,6 +1880,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_REBOOT = 1, /* virConnectDomainEventGenericCallback */ VIR_DOMAIN_EVENT_ID_RTC_CHANGE = 2, /* virConnectDomainEventRTCChangeCallback */ VIR_DOMAIN_EVENT_ID_WATCHDOG = 3, /* virConnectDomainEventWatchdogCallback */ + VIR_DOMAIN_EVENT_ID_IO_ERROR = 4, /* virConnectDomainEventIOErrorCallback */ /* * NB: this enum value will increase over time as new events are diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 4482599..77b52ef 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -70,6 +70,11 @@ struct _virDomainEvent { struct { int action; } watchdog; + struct { + char *srcPath; + char *devAlias; + int action; + } ioError; } data; }; @@ -458,6 +463,11 @@ void virDomainEventFree(virDomainEventPtr event) if (!event) return; + if (event->eventID == VIR_DOMAIN_EVENT_ID_IO_ERROR) { + VIR_FREE(event->data.ioError.srcPath); + VIR_FREE(event->data.ioError.devAlias); + } + VIR_FREE(event->dom.name); VIR_FREE(event); } @@ -590,6 +600,47 @@ virDomainEventPtr virDomainEventWatchdogNewFromObj(virDomainObjPtr obj, return ev; } +virDomainEventPtr virDomainEventIOErrorNewFromDom(virDomainPtr dom, + const char *srcPath, + const char *devAlias, + int action) +{ + virDomainEventPtr ev = + virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_IO_ERROR, + dom->id, dom->name, dom->uuid); + + if (ev) { + ev->data.ioError.action = action; + if (!(ev->data.ioError.srcPath = strdup(srcPath)) || + !(ev->data.ioError.devAlias = strdup(devAlias))) { + virDomainEventFree(ev); + ev = NULL; + } + } + + return ev; +} +virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj, + const char *srcPath, + const char *devAlias, + int action) +{ + virDomainEventPtr ev = + virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_IO_ERROR, + obj->def->id, obj->def->name, obj->def->uuid); + + if (ev) { + ev->data.watchdog.action = action; + if (!(ev->data.ioError.srcPath = strdup(srcPath)) || + !(ev->data.ioError.devAlias = strdup(devAlias))) { + virDomainEventFree(ev); + ev = NULL; + } + } + + return ev; +} + /** * virDomainEventQueueFree: * @queue: pointer to the queue @@ -712,6 +763,14 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn, cbopaque); break; + case VIR_DOMAIN_EVENT_ID_IO_ERROR: + ((virConnectDomainEventIOErrorCallback)cb)(conn, dom, + event->data.ioError.srcPath, + event->data.ioError.devAlias, + event->data.ioError.action, + 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 b791614..dbf9288 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -121,6 +121,15 @@ virDomainEventPtr virDomainEventRTCChangeNewFromObj(virDomainObjPtr obj, long lo virDomainEventPtr virDomainEventWatchdogNewFromDom(virDomainPtr dom, int action); virDomainEventPtr virDomainEventWatchdogNewFromObj(virDomainObjPtr obj, int action); +virDomainEventPtr virDomainEventIOErrorNewFromDom(virDomainPtr dom, + const char *srcPath, + const char *devAlias, + int action); +virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj, + const char *srcPath, + const char *devAlias, + int action); + int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue, virDomainEventPtr event); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 17902b1..4578762 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -220,6 +220,8 @@ virDomainEventRTCChangeNewFromDom; virDomainEventRTCChangeNewFromObj; virDomainEventWatchdogNewFromDom; virDomainEventWatchdogNewFromObj; +virDomainEventIOErrorNewFromDom; +virDomainEventIOErrorNewFromObj; virDomainEventFree; virDomainEventDispatchDefaultFunc; virDomainEventDispatch; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ceba5db..71cca5c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -747,6 +747,26 @@ findDomainDiskByPath(virDomainObjPtr vm, return NULL; } +static virDomainDiskDefPtr +findDomainDiskByAlias(virDomainObjPtr vm, + const char *alias) +{ + int i; + + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr disk; + + disk = vm->def->disks[i]; + if (disk->info.alias != NULL && STREQ(disk->info.alias, alias)) + return disk; + } + + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("no disk found with alias %s"), + alias); + return NULL; +} + static int getVolumeQcowPassphrase(virConnectPtr conn, virDomainDiskDefPtr disk, @@ -928,12 +948,49 @@ qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED, } +static int +qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + const char *diskAlias, + int action) +{ + struct qemud_driver *driver = qemu_driver; + virDomainEventPtr event; + const char *srcPath; + const char *devAlias; + virDomainDiskDefPtr disk; + + virDomainObjLock(vm); + disk = findDomainDiskByAlias(vm, diskAlias); + + if (disk) { + srcPath = disk->src; + devAlias = disk->info.alias; + } else { + srcPath = ""; + devAlias = ""; + } + + event = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action); + virDomainObjUnlock(vm); + + if (event) { + qemuDriverLock(driver); + qemuDomainEventQueue(driver, event); + qemuDriverUnlock(driver); + } + + return 0; +} + + static qemuMonitorCallbacks monitorCallbacks = { .eofNotify = qemuHandleMonitorEOF, .diskSecretLookup = findVolumeQcowPassphrase, .domainReset = qemuHandleDomainReset, .domainRTCChange = qemuHandleDomainRTCChange, .domainWatchdog = qemuHandleDomainWatchdog, + .domainIOError = qemuHandleDomainIOError, }; static int diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index d7116c9..f320df9 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -821,6 +821,23 @@ int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action) } +int qemuMonitorEmitIOError(qemuMonitorPtr mon, + const char *diskAlias, + int action) +{ + int ret = -1; + VIR_DEBUG("mon=%p", mon); + + qemuMonitorRef(mon); + qemuMonitorUnlock(mon); + if (mon->cb && mon->cb->domainIOError) + ret = mon->cb->domainIOError(mon, mon->vm, diskAlias, action); + qemuMonitorLock(mon); + qemuMonitorUnref(mon); + return ret; +} + + int qemuMonitorSetCapabilities(qemuMonitorPtr mon) { int ret; diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 3558dba..64ae153 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -92,6 +92,10 @@ struct _qemuMonitorCallbacks { int (*domainWatchdog)(qemuMonitorPtr mon, virDomainObjPtr vm, int action); + int (*domainIOError)(qemuMonitorPtr mon, + virDomainObjPtr vm, + const char *diskAlias, + int action); }; @@ -130,6 +134,9 @@ int qemuMonitorEmitPowerdown(qemuMonitorPtr mon); int qemuMonitorEmitStop(qemuMonitorPtr mon); int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset); int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action); +int qemuMonitorEmitIOError(qemuMonitorPtr mon, + const char *diskAlias, + int action); int qemuMonitorStartCPUs(qemuMonitorPtr mon, virConnectPtr conn); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index d7fbf38..e2d7744 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -51,6 +51,7 @@ static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr d static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data); static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data); +static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data); struct { const char *type; @@ -62,6 +63,7 @@ struct { { "STOP", qemuMonitorJSONHandleStop, }, { "RTC_CHANGE", qemuMonitorJSONHandleRTCChange, }, { "WATCHDOG", qemuMonitorJSONHandleWatchdog, }, + { "DISK_IO_ERROR", qemuMonitorJSONHandleIOError, }, }; @@ -510,8 +512,8 @@ static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr d } VIR_ENUM_DECL(qemuMonitorWatchdogAction) -VIR_ENUM_IMPL(qemuMonitorWatchdogAction, VIR_DOMAIN_EVENT_WATCHDOG_DEBUG, - "none", "pause", "reset", "poweroff" "shutdown", "debug"); +VIR_ENUM_IMPL(qemuMonitorWatchdogAction, VIR_DOMAIN_EVENT_WATCHDOG_DEBUG + 1, + "none", "pause", "reset", "poweroff", "shutdown", "debug"); static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data) { @@ -531,6 +533,38 @@ static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr da qemuMonitorEmitRTCChange(mon, actionID); } +VIR_ENUM_DECL(qemuMonitorIOErrorAction) +VIR_ENUM_IMPL(qemuMonitorIOErrorAction, VIR_DOMAIN_EVENT_IO_ERROR_REPORT + 1, + "ignore", "stop", "report"); + + +static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data) +{ + const char *device; + const char *action; + int actionID; + + /* Throughout here we try our best to carry on upon errors, + since its imporatant to get as much info as possible out + to the application */ + + if ((action = virJSONValueObjectGetString(data, "action")) == NULL) { + VIR_WARN0("Missing action in disk io error event"); + action = "ignore"; + } + + if ((device = virJSONValueObjectGetString(data, "device")) == NULL) { + VIR_WARN0("missing device in disk io error event"); + } + + if ((actionID = qemuMonitorIOErrorActionTypeFromString(action)) < 0) { + VIR_WARN("unknown disk io error action '%s'", action); + actionID = VIR_DOMAIN_EVENT_IO_ERROR_NONE; + } + + qemuMonitorEmitIOError(mon, device, actionID); +} + int qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8652083..068ad9b 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6968,6 +6968,36 @@ remoteDomainReadEventWatchdog(virConnectPtr conn, XDR *xdr) } +static virDomainEventPtr +remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr) +{ + remote_domain_event_io_error_msg msg; + virDomainPtr dom; + virDomainEventPtr event = NULL; + memset (&msg, 0, sizeof msg); + + /* unmarshall parameters, and process it*/ + if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) { + error (conn, VIR_ERR_RPC, + _("unable to demarshall reboot event")); + return NULL; + } + + dom = get_nonnull_domain(conn,msg.dom); + if (!dom) + return NULL; + + event = virDomainEventIOErrorNewFromDom(dom, + msg.srcPath, + msg.devAlias, + msg.action); + xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_msg, (char *) &msg); + + virDomainFree(dom); + return event; +} + + static virDrvOpenStatus ATTRIBUTE_NONNULL (1) remoteSecretOpen (virConnectPtr conn, virConnectAuthPtr auth, @@ -8493,6 +8523,10 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, event = remoteDomainReadEventWatchdog(conn, xdr); break; + case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR: + event = remoteDomainReadEventIOError(conn, xdr); + break; + default: DEBUG("Unexpected event proc %d", hdr->proc); break; diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 8a6c353..79dfb98 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3058,6 +3058,21 @@ xdr_remote_domain_event_watchdog_msg (XDR *xdrs, remote_domain_event_watchdog_ms } bool_t +xdr_remote_domain_event_io_error_msg (XDR *xdrs, remote_domain_event_io_error_msg *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->srcPath)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->devAlias)) + return FALSE; + if (!xdr_int (xdrs, &objp->action)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index f68989f..cddd284 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -1731,6 +1731,14 @@ struct remote_domain_event_watchdog_msg { int action; }; typedef struct remote_domain_event_watchdog_msg remote_domain_event_watchdog_msg; + +struct remote_domain_event_io_error_msg { + remote_nonnull_domain dom; + remote_nonnull_string srcPath; + remote_nonnull_string devAlias; + int action; +}; +typedef struct remote_domain_event_io_error_msg remote_domain_event_io_error_msg; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1904,6 +1912,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_REBOOT = 167, REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 168, REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 169, + REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 170, }; typedef enum remote_procedure remote_procedure; @@ -2218,6 +2227,7 @@ extern bool_t xdr_remote_domain_events_deregister_any_args (XDR *, remote_domai extern bool_t xdr_remote_domain_event_reboot_msg (XDR *, remote_domain_event_reboot_msg*); extern bool_t xdr_remote_domain_event_rtc_change_msg (XDR *, remote_domain_event_rtc_change_msg*); extern bool_t xdr_remote_domain_event_watchdog_msg (XDR *, remote_domain_event_watchdog_msg*); +extern bool_t xdr_remote_domain_event_io_error_msg (XDR *, remote_domain_event_io_error_msg*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -2506,6 +2516,7 @@ extern bool_t xdr_remote_domain_events_deregister_any_args (); extern bool_t xdr_remote_domain_event_reboot_msg (); extern bool_t xdr_remote_domain_event_rtc_change_msg (); extern bool_t xdr_remote_domain_event_watchdog_msg (); +extern bool_t xdr_remote_domain_event_io_error_msg (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index f793968..3cdc99b 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1539,6 +1539,13 @@ struct remote_domain_event_watchdog_msg { int action; }; +struct remote_domain_event_io_error_msg { + remote_nonnull_domain dom; + remote_nonnull_string srcPath; + remote_nonnull_string devAlias; + int action; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1730,7 +1737,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 166, REMOTE_PROC_DOMAIN_EVENT_REBOOT = 167, REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 168, - REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 169 + REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 169, + REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 170 /* * Notice how the entries are grouped in sets of 10 ? -- 1.6.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list