}
+static int
+remoteRelayDomainEventBlockThreshold(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_block_threshold_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain block threshold event %s %d %s %s %llu %llu, callback %d",
+ dom->name, dom->id, dev, NULLSTR(path), threshold, excess, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ if (VIR_STRDUP(data.dev, dev) < 0)
+ goto error;
+ if (path) {
+ if (VIR_ALLOC(data.path) < 0)
+ goto error;
+ if (VIR_STRDUP(*(data.path), path) < 0)
+ goto error;
+ }
+ data.threshold = threshold;
+ data.excess = excess;
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD,
+ (xdrproc_t)xdr_remote_domain_event_block_threshold_msg, &data);
+
+ return 0;
+ error:
+ VIR_FREE(data.dev);
+ return -1;
+}
+
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
#define ARRAY_CARDINALITY(Array) (sizeof(Array) / sizeof(*(Array)))
#define STREQ(a, b) (strcmp(a, b) == 0)
+#define NULLSTR(s) ((s) ? (s) : "<null>")
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__((__unused__))
}
+static int
+myDomainEventBlockThresholdCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ printf("%s EVENT: Domain %s(%d) block threshold callback dev '%s'(%s), "
+ "threshold: '%llu', excess: '%llu'",
+ __func__, virDomainGetName(dom), virDomainGetID(dom),
+ dev, NULLSTR(path), threshold, excess);
+ return 0;
+}
+
+
static int
myDomainEventMigrationIterationCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback),
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),
};
struct storagePoolEventData {
void *opaque);
+/**
+ * virConnectDomainEventBlockThresholdCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @dev: name associated with the affected disk or storage backing chain
+ * element
+ * @path: for local storage, the path of the backing chain element
+ * @threshold: threshold offset in bytes
+ * @excess: number of bytes written beyond the threshold
+ * @opaque: application specified data
+ *
+ * The callback occurs when the hypervisor detects that the given storage
+ * element was written beyond the point specified by @threshold. The excess
+ * data size written beyond @threshold is reported by @excess (if supported
+ * by the hypervisor, 0 otherwise). The event is useful for thin-provisioned
+ * storage.
+ *
+ * The threshold size can be set via the virDomainSetBlockThreshold API.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventBlockThresholdCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess,
+ void *opaque);
+
/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
VIR_DOMAIN_EVENT_ID_JOB_COMPLETED = 21, /* virConnectDomainEventJobCompletedCallback */
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 */
# ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_ID_LAST
static virClassPtr virDomainEventJobCompletedClass;
static virClassPtr virDomainEventDeviceRemovalFailedClass;
static virClassPtr virDomainEventMetadataChangeClass;
+static virClassPtr virDomainEventBlockThresholdClass;
static void virDomainEventDispose(void *obj);
static void virDomainEventLifecycleDispose(void *obj);
static void virDomainEventJobCompletedDispose(void *obj);
static void virDomainEventDeviceRemovalFailedDispose(void *obj);
static void virDomainEventMetadataChangeDispose(void *obj);
+static void virDomainEventBlockThresholdDispose(void *obj);
static void
virDomainEventDispatchDefaultFunc(virConnectPtr conn,
typedef struct _virDomainEventMetadataCange virDomainEventMetadataChange;
typedef virDomainEventMetadataChange *virDomainEventMetadataChangePtr;
+struct _virDomainEventBlockThreshold {
+ virDomainEvent parent;
+
+ char *dev;
+ char *path;
+
+ unsigned long long threshold;
+ unsigned long long excess;
+};
+typedef struct _virDomainEventBlockThreshold virDomainEventBlockThreshold;
+typedef virDomainEventBlockThreshold *virDomainEventBlockThresholdPtr;
static int
sizeof(virDomainEventMetadataChange),
virDomainEventMetadataChangeDispose)))
return -1;
+ if (!(virDomainEventBlockThresholdClass =
+ virClassNew(virDomainEventClass,
+ "virDomainEventBlockThreshold",
+ sizeof(virDomainEventBlockThreshold),
+ virDomainEventBlockThresholdDispose)))
+ return -1;
return 0;
}
}
+static void
+virDomainEventBlockThresholdDispose(void *obj)
+{
+ virDomainEventBlockThresholdPtr event = obj;
+ VIR_DEBUG("obj=%p", event);
+
+ VIR_FREE(event->dev);
+ VIR_FREE(event->path);
+}
+
+
static void *
virDomainEventNew(virClassPtr klass,
int eventID,
}
+static virObjectEventPtr
+virDomainEventBlockThresholdNew(int id,
+ const char *name,
+ unsigned char *uuid,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess)
+{
+ virDomainEventBlockThresholdPtr ev;
+
+ if (virDomainEventsInitialize() < 0)
+ return NULL;
+
+ if (!(ev = virDomainEventNew(virDomainEventBlockThresholdClass,
+ VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD,
+ id, name, uuid)))
+ return NULL;
+
+ if (VIR_STRDUP(ev->dev, dev) < 0 ||
+ VIR_STRDUP(ev->path, path) < 0) {
+ virObjectUnref(ev);
+ return NULL;
+ }
+ ev->threshold = threshold;
+ ev->excess = excess;
+
+ return (virObjectEventPtr)ev;
+}
+
+virObjectEventPtr
+virDomainEventBlockThresholdNewFromObj(virDomainObjPtr obj,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess)
+{
+ return virDomainEventBlockThresholdNew(obj->def->id, obj->def->name,
+ obj->def->uuid, dev, path,
+ threshold, excess);
+}
+
+virObjectEventPtr
+virDomainEventBlockThresholdNewFromDom(virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess)
+{
+ return virDomainEventBlockThresholdNew(dom->id, dom->name, dom->uuid,
+ dev, path, threshold, excess);
+}
+
+
static void
virDomainEventDispatchDefaultFunc(virConnectPtr conn,
virObjectEventPtr event,
goto cleanup;
}
+ case VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD:
+ {
+ virDomainEventBlockThresholdPtr blockThresholdEvent;
+
+ blockThresholdEvent = (virDomainEventBlockThresholdPtr)event;
+ ((virConnectDomainEventBlockThresholdCallback)cb)(conn, dom,
+ blockThresholdEvent->dev,
+ blockThresholdEvent->path,
+ blockThresholdEvent->threshold,
+ blockThresholdEvent->excess,
+ cbopaque);
+ goto cleanup;
+ }
case VIR_DOMAIN_EVENT_ID_LAST:
break;
}
int type,
const char *nsuri);
+
+virObjectEventPtr
+virDomainEventBlockThresholdNewFromObj(virDomainObjPtr obj,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess);
+
+virObjectEventPtr
+virDomainEventBlockThresholdNewFromDom(virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess);
+
int
virDomainEventStateRegister(virConnectPtr conn,
virObjectEventStatePtr state,
virDomainEventBlockJob2NewFromObj;
virDomainEventBlockJobNewFromDom;
virDomainEventBlockJobNewFromObj;
+virDomainEventBlockThresholdNewFromDom;
+virDomainEventBlockThresholdNewFromObj;
virDomainEventControlErrorNewFromDom;
virDomainEventControlErrorNewFromObj;
virDomainEventDeviceAddedNewFromDom;
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventBlockThreshold(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
static void
remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
remoteSecretBuildEventValueChanged,
sizeof(remote_secret_event_value_changed_msg),
(xdrproc_t)xdr_remote_secret_event_value_changed_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD,
+ remoteDomainBuildEventBlockThreshold,
+ sizeof(remote_domain_event_block_threshold_msg),
+ (xdrproc_t)xdr_remote_domain_event_block_threshold_msg },
};
static void
}
+static void
+remoteDomainBuildEventBlockThreshold(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ remote_domain_event_block_threshold_msg *msg = evdata;
+ struct private_data *priv = conn->privateData;
+ virDomainPtr dom;
+ virObjectEventPtr event = NULL;
+
+ if (!(dom = get_nonnull_domain(conn, msg->dom)))
+ return;
+
+ event = virDomainEventBlockThresholdNewFromDom(dom, msg->dev,
+ msg->path ? *msg->path : NULL,
+ msg->threshold, msg->excess);
+
+ virObjectUnref(dom);
+
+ remoteEventQueue(priv, event, msg->callbackID);
+}
+
+
static int
remoteStreamSend(virStreamPtr st,
const char *data,
int status;
};
+struct remote_domain_event_block_threshold_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_nonnull_string dev;
+ remote_string path;
+ unsigned hyper threshold;
+ unsigned hyper excess;
+};
+
struct remote_domain_event_callback_tunable_msg {
int callbackID;
remote_nonnull_domain dom;
* @acl: domain:save:!VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE
* @acl: domain:save:VIR_DOMAIN_AFFECT_CONFIG
*/
- REMOTE_PROC_DOMAIN_SET_VCPU = 384
+ REMOTE_PROC_DOMAIN_SET_VCPU = 384,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD = 385
+
};
int type;
int status;
};
+struct remote_domain_event_block_threshold_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_nonnull_string dev;
+ remote_string path;
+ uint64_t threshold;
+ uint64_t excess;
+};
struct remote_domain_event_callback_tunable_msg {
int callbackID;
remote_nonnull_domain dom;
REMOTE_PROC_SECRET_EVENT_LIFECYCLE = 382,
REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED = 383,
REMOTE_PROC_DOMAIN_SET_VCPU = 384,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD = 385,
};
}
+static void
+virshEventBlockThresholdPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess,
+ void *opaque)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'block-threshold' for domain %s: "
+ "dev: %s(%s) %llu %llu\n"),
+ virDomainGetName(dom),
+ dev, NULLSTR(path), threshold, excess);
+ virshEventPrint(opaque, &buf);
+}
+
+
static vshEventCallback vshEventCallbacks[] = {
{ "lifecycle",
VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovalFailedPrint), },
{ "metadata-change",
VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), },
+ { "block-threshold",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), },
};
verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));