1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-22 17:34:18 +03:00

Add support for another explicit IO error event

This introduces a new event type

   VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON

This event is the same as the previous VIR_DOMAIN_ID_IO_ERROR
event, but also includes a string describing the cause of
the event.

Thus there is a new callback definition for this event type

typedef void (*virConnectDomainEventIOErrorReasonCallback)(virConnectPtr conn,
                                                           virDomainPtr dom,
                                                           const char *srcPath,
                                                           const char *devAlias,
                                                           int action,
                                                           const char *reason,
                                                           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
This commit is contained in:
Daniel P. Berrange 2010-03-18 19:37:44 +00:00
parent c90a1ad7d0
commit 34dcbbb470
16 changed files with 313 additions and 21 deletions

View File

@ -256,6 +256,43 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
}
static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason,
void *opaque)
{
struct qemud_client *client = opaque;
remote_domain_event_io_error_reason_msg data;
if (!client)
return -1;
REMOTE_DEBUG("Relaying domain io error %s %d %s %s %d %s",
dom->name, dom->id, srcPath, devAlias, action, reason);
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;
data.reason = (char*)reason;
remoteDispatchDomainEventSend (client,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
(xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);
virMutexUnlock(&client->lock);
return 0;
}
static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int phase,
@ -327,6 +364,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);

View File

@ -977,3 +977,8 @@
.args_filter = (xdrproc_t) xdr_remote_domain_get_block_info_args,
.ret_filter = (xdrproc_t) xdr_remote_domain_get_block_info_ret,
},
{ /* Async event DomainEventIoErrorReason => 195 */
.fn = NULL,
.args_filter = (xdrproc_t) xdr_void,
.ret_filter = (xdrproc_t) xdr_void,
},

View File

@ -2053,6 +2053,28 @@ typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
int action,
void *opaque);
/**
* virConnectDomainEventWatchdogCallback:
* @conn: connection object
* @dom: domain on which the event occurred
* @srcPath: The host file on which the IO error occurred
* @devAlias: The guest device alias associated with the path
* @action: action that is to be taken due to the IO error
* @reason: the cause of the IO error
* @opaque: application specified data
*
* The callback signature to use when registering for an event of type
* VIR_DOMAIN_EVENT_ID_IO_ERROR with virConnectDomainEventRegisterAny()
*
*/
typedef void (*virConnectDomainEventIOErrorReasonCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason,
void *opaque);
/**
* virDomainEventGraphicsPhase:
*
@ -2161,6 +2183,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_WATCHDOG = 3, /* virConnectDomainEventWatchdogCallback */
VIR_DOMAIN_EVENT_ID_IO_ERROR = 4, /* virConnectDomainEventIOErrorCallback */
VIR_DOMAIN_EVENT_ID_GRAPHICS = 5, /* virConnectDomainEventGraphicsCallback */
VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON = 6, /* virConnectDomainEventIOErrorReasonCallback */
/*
* NB: this enum value will increase over time as new events are

View File

@ -94,7 +94,19 @@
cb = cbData["cb"]
opaque = cbData["opaque"]
cb(self, virDomain(self, _obj=dom), opaque)
cb(self, virDomain(self, _obj=dom), srcPath, devAlias, opaque)
return 0
except AttributeError:
pass
def dispatchDomainEventIOErrorReasonCallback(self, dom, srcPath, devAlias, action, reason, cbData):
"""Dispatches events to python user domain IO error event callbacks
"""
try:
cb = cbData["cb"]
opaque = cbData["opaque"]
cb(self, virDomain(self, _obj=dom), srcPath, devAlias, action, reason, opaque)
return 0
except AttributeError:
pass

View File

@ -3207,6 +3207,58 @@ libvirt_virConnectDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED
return ret;
}
static int
libvirt_virConnectDomainEventIOErrorReasonCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason,
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*)"dispatchDomainEventIOErrorCallback",
(char*)"OssisO",
pyobj_dom,
srcPath, devAlias, action, reason,
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 int
libvirt_virConnectDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
@ -3345,6 +3397,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
case VIR_DOMAIN_EVENT_ID_IO_ERROR:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventIOErrorCallback);
break;
case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventIOErrorReasonCallback);
break;
case VIR_DOMAIN_EVENT_ID_GRAPHICS:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventGraphicsCallback);
break;

View File

@ -74,6 +74,7 @@ struct _virDomainEvent {
char *srcPath;
char *devAlias;
int action;
char *reason;
} ioError;
struct {
int phase;
@ -474,6 +475,7 @@ void virDomainEventFree(virDomainEventPtr event)
case VIR_DOMAIN_EVENT_ID_IO_ERROR:
VIR_FREE(event->data.ioError.srcPath);
VIR_FREE(event->data.ioError.devAlias);
VIR_FREE(event->data.ioError.reason);
break;
case VIR_DOMAIN_EVENT_ID_GRAPHICS:
@ -630,19 +632,22 @@ virDomainEventPtr virDomainEventWatchdogNewFromObj(virDomainObjPtr obj,
return ev;
}
virDomainEventPtr virDomainEventIOErrorNewFromDom(virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action)
static virDomainEventPtr virDomainEventIOErrorNewFromDomImpl(int event,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason)
{
virDomainEventPtr ev =
virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_IO_ERROR,
virDomainEventNewInternal(event,
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))) {
!(ev->data.ioError.devAlias = strdup(devAlias)) ||
(reason && !(ev->data.ioError.reason = strdup(reason)))) {
virDomainEventFree(ev);
ev = NULL;
}
@ -650,19 +655,23 @@ virDomainEventPtr virDomainEventIOErrorNewFromDom(virDomainPtr dom,
return ev;
}
virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj,
const char *srcPath,
const char *devAlias,
int action)
static virDomainEventPtr virDomainEventIOErrorNewFromObjImpl(int event,
virDomainObjPtr obj,
const char *srcPath,
const char *devAlias,
int action,
const char *reason)
{
virDomainEventPtr ev =
virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_IO_ERROR,
virDomainEventNewInternal(event,
obj->def->id, obj->def->name, obj->def->uuid);
if (ev) {
ev->data.ioError.action = action;
if (!(ev->data.ioError.srcPath = strdup(srcPath)) ||
!(ev->data.ioError.devAlias = strdup(devAlias))) {
!(ev->data.ioError.devAlias = strdup(devAlias)) ||
!(ev->data.ioError.reason = strdup(reason))) {
virDomainEventFree(ev);
ev = NULL;
}
@ -671,6 +680,48 @@ virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj,
return ev;
}
virDomainEventPtr virDomainEventIOErrorNewFromDom(virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action)
{
return virDomainEventIOErrorNewFromDomImpl(VIR_DOMAIN_EVENT_ID_IO_ERROR,
dom, srcPath, devAlias,
action, NULL);
}
virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj,
const char *srcPath,
const char *devAlias,
int action)
{
return virDomainEventIOErrorNewFromObjImpl(VIR_DOMAIN_EVENT_ID_IO_ERROR,
obj, srcPath, devAlias,
action, NULL);
}
virDomainEventPtr virDomainEventIOErrorReasonNewFromDom(virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason)
{
return virDomainEventIOErrorNewFromDomImpl(VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON,
dom, srcPath, devAlias,
action, reason);
}
virDomainEventPtr virDomainEventIOErrorReasonNewFromObj(virDomainObjPtr obj,
const char *srcPath,
const char *devAlias,
int action,
const char *reason)
{
return virDomainEventIOErrorNewFromObjImpl(VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON,
obj, srcPath, devAlias,
action, reason);
}
virDomainEventPtr virDomainEventGraphicsNewFromDom(virDomainPtr dom,
int phase,
@ -853,6 +904,15 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
((virConnectDomainEventIOErrorReasonCallback)cb)(conn, dom,
event->data.ioError.srcPath,
event->data.ioError.devAlias,
event->data.ioError.action,
event->data.ioError.reason,
cbopaque);
break;
case VIR_DOMAIN_EVENT_ID_GRAPHICS:
((virConnectDomainEventGraphicsCallback)cb)(conn, dom,
event->data.graphics.phase,

View File

@ -129,6 +129,16 @@ virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj,
const char *srcPath,
const char *devAlias,
int action);
virDomainEventPtr virDomainEventIOErrorReasonNewFromDom(virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason);
virDomainEventPtr virDomainEventIOErrorReasonNewFromObj(virDomainObjPtr obj,
const char *srcPath,
const char *devAlias,
int action,
const char *reason);
virDomainEventPtr virDomainEventGraphicsNewFromDom(virDomainPtr dom,
int phase,

View File

@ -246,6 +246,8 @@ virDomainEventWatchdogNewFromDom;
virDomainEventWatchdogNewFromObj;
virDomainEventIOErrorNewFromDom;
virDomainEventIOErrorNewFromObj;
virDomainEventIOErrorReasonNewFromDom;
virDomainEventIOErrorReasonNewFromObj;
virDomainEventGraphicsNewFromDom;
virDomainEventGraphicsNewFromObj;
virDomainEventFree;

View File

@ -1015,10 +1015,12 @@ static int
qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
const char *diskAlias,
int action)
int action,
const char *reason)
{
struct qemud_driver *driver = qemu_driver;
virDomainEventPtr ioErrorEvent = NULL;
virDomainEventPtr ioErrorEvent2 = NULL;
virDomainEventPtr lifecycleEvent = NULL;
const char *srcPath;
const char *devAlias;
@ -1036,6 +1038,7 @@ qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
}
ioErrorEvent = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);
ioErrorEvent2 = virDomainEventIOErrorReasonNewFromObj(vm, srcPath, devAlias, action, reason);
if (action == VIR_DOMAIN_EVENT_IO_ERROR_PAUSE &&
vm->state == VIR_DOMAIN_RUNNING) {
@ -1051,10 +1054,12 @@ qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
}
virDomainObjUnlock(vm);
if (ioErrorEvent || lifecycleEvent) {
if (ioErrorEvent || ioErrorEvent2 || lifecycleEvent) {
qemuDriverLock(driver);
if (ioErrorEvent)
qemuDomainEventQueue(driver, ioErrorEvent);
if (ioErrorEvent2)
qemuDomainEventQueue(driver, ioErrorEvent2);
if (lifecycleEvent)
qemuDomainEventQueue(driver, lifecycleEvent);
qemuDriverUnlock(driver);

View File

@ -833,7 +833,8 @@ int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action)
int qemuMonitorEmitIOError(qemuMonitorPtr mon,
const char *diskAlias,
int action)
int action,
const char *reason)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
@ -841,7 +842,7 @@ int qemuMonitorEmitIOError(qemuMonitorPtr mon,
qemuMonitorRef(mon);
qemuMonitorUnlock(mon);
if (mon->cb && mon->cb->domainIOError)
ret = mon->cb->domainIOError(mon, mon->vm, diskAlias, action);
ret = mon->cb->domainIOError(mon, mon->vm, diskAlias, action, reason);
qemuMonitorLock(mon);
qemuMonitorUnref(mon);
return ret;

View File

@ -95,7 +95,8 @@ struct _qemuMonitorCallbacks {
int (*domainIOError)(qemuMonitorPtr mon,
virDomainObjPtr vm,
const char *diskAlias,
int action);
int action,
const char *reason);
int (*domainGraphics)(qemuMonitorPtr mon,
virDomainObjPtr vm,
int phase,
@ -148,7 +149,8 @@ int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset);
int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action);
int qemuMonitorEmitIOError(qemuMonitorPtr mon,
const char *diskAlias,
int action);
int action,
const char *reason);
int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
int phase,
int localFamily,

View File

@ -514,6 +514,7 @@ static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr dat
{
const char *device;
const char *action;
const char *reason;
int actionID;
/* Throughout here we try our best to carry on upon errors,
@ -529,12 +530,17 @@ static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr dat
VIR_WARN0("missing device in disk io error event");
}
if ((reason = virJSONValueObjectGetString(data, "reason")) == NULL) {
VIR_WARN0("missing reason in disk io error event");
reason = "";
}
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);
qemuMonitorEmitIOError(mon, device, actionID, reason);
}

View File

@ -7429,6 +7429,37 @@ remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr)
}
static virDomainEventPtr
remoteDomainReadEventIOErrorReason(virConnectPtr conn, XDR *xdr)
{
remote_domain_event_io_error_reason_msg msg;
virDomainPtr dom;
virDomainEventPtr event = NULL;
memset (&msg, 0, sizeof msg);
/* unmarshall parameters, and process it*/
if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) {
remoteError(VIR_ERR_RPC, "%s",
_("unable to demarshall reboot event"));
return NULL;
}
dom = get_nonnull_domain(conn,msg.dom);
if (!dom)
return NULL;
event = virDomainEventIOErrorReasonNewFromDom(dom,
msg.srcPath,
msg.devAlias,
msg.action,
msg.reason);
xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_reason_msg, (char *) &msg);
virDomainFree(dom);
return event;
}
static virDomainEventPtr
remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
{
@ -9327,6 +9358,10 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
event = remoteDomainReadEventIOError(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON:
event = remoteDomainReadEventIOErrorReason(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS:
event = remoteDomainReadEventGraphics(conn, xdr);
break;

View File

@ -3289,6 +3289,23 @@ xdr_remote_domain_event_io_error_msg (XDR *xdrs, remote_domain_event_io_error_ms
return TRUE;
}
bool_t
xdr_remote_domain_event_io_error_reason_msg (XDR *xdrs, remote_domain_event_io_error_reason_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;
if (!xdr_remote_nonnull_string (xdrs, &objp->reason))
return FALSE;
return TRUE;
}
bool_t
xdr_remote_domain_event_graphics_address (XDR *xdrs, remote_domain_event_graphics_address *objp)
{

View File

@ -1864,6 +1864,15 @@ struct remote_domain_event_io_error_msg {
};
typedef struct remote_domain_event_io_error_msg remote_domain_event_io_error_msg;
struct remote_domain_event_io_error_reason_msg {
remote_nonnull_domain dom;
remote_nonnull_string srcPath;
remote_nonnull_string devAlias;
int action;
remote_nonnull_string reason;
};
typedef struct remote_domain_event_io_error_reason_msg remote_domain_event_io_error_reason_msg;
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
@ -2206,6 +2215,7 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_REVERT_TO_SNAPSHOT = 192,
REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 193,
REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195,
};
typedef enum remote_procedure remote_procedure;
@ -2541,6 +2551,7 @@ extern bool_t xdr_remote_domain_event_reboot_msg (XDR *, remote_domain_event_re
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_domain_event_io_error_reason_msg (XDR *, remote_domain_event_io_error_reason_msg*);
extern bool_t xdr_remote_domain_event_graphics_address (XDR *, remote_domain_event_graphics_address*);
extern bool_t xdr_remote_domain_event_graphics_identity (XDR *, remote_domain_event_graphics_identity*);
extern bool_t xdr_remote_domain_event_graphics_msg (XDR *, remote_domain_event_graphics_msg*);
@ -2873,6 +2884,7 @@ 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_domain_event_io_error_reason_msg ();
extern bool_t xdr_remote_domain_event_graphics_address ();
extern bool_t xdr_remote_domain_event_graphics_identity ();
extern bool_t xdr_remote_domain_event_graphics_msg ();

View File

@ -1659,6 +1659,14 @@ struct remote_domain_event_io_error_msg {
int action;
};
struct remote_domain_event_io_error_reason_msg {
remote_nonnull_domain dom;
remote_nonnull_string srcPath;
remote_nonnull_string devAlias;
int action;
remote_nonnull_string reason;
};
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
@ -1996,7 +2004,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT = 191,
REMOTE_PROC_DOMAIN_REVERT_TO_SNAPSHOT = 192,
REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 193,
REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194
REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195
/*
* Notice how the entries are grouped in sets of 10 ?