mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
lib: Introduce event for tracking disk backing file write threshold
When using thin provisioning, management tools need to resize the disk in certain cases. To avoid having them to poll disk usage introduce an event which will be fired when a given offset of the storage is written by the hypervisor. Together with the API which will be added later, it will allow registering thresholds for given storage backing volumes and this event will then notify management if the threshold is exceeded.
This commit is contained in:
parent
cbc6d53513
commit
085e794a86
@ -1295,6 +1295,50 @@ remoteRelayDomainEventMetadataChange(virConnectPtr conn,
|
||||
}
|
||||
|
||||
|
||||
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),
|
||||
@ -1321,6 +1365,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
|
||||
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);
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#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__))
|
||||
@ -924,6 +925,23 @@ myDomainEventBlockJobCallback(virConnectPtr conn 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,
|
||||
@ -1053,6 +1071,7 @@ struct domainEventData domainEvents[] = {
|
||||
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 {
|
||||
|
@ -4274,6 +4274,36 @@ typedef void (*virConnectDomainEventAgentLifecycleCallback)(virConnectPtr conn,
|
||||
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:
|
||||
*
|
||||
@ -4315,6 +4345,7 @@ typedef enum {
|
||||
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
|
||||
|
@ -60,6 +60,7 @@ static virClassPtr virDomainEventMigrationIterationClass;
|
||||
static virClassPtr virDomainEventJobCompletedClass;
|
||||
static virClassPtr virDomainEventDeviceRemovalFailedClass;
|
||||
static virClassPtr virDomainEventMetadataChangeClass;
|
||||
static virClassPtr virDomainEventBlockThresholdClass;
|
||||
|
||||
static void virDomainEventDispose(void *obj);
|
||||
static void virDomainEventLifecycleDispose(void *obj);
|
||||
@ -81,6 +82,7 @@ static void virDomainEventMigrationIterationDispose(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,
|
||||
@ -277,6 +279,17 @@ struct _virDomainEventMetadataCange {
|
||||
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
|
||||
@ -402,6 +415,12 @@ virDomainEventsOnceInit(void)
|
||||
sizeof(virDomainEventMetadataChange),
|
||||
virDomainEventMetadataChangeDispose)))
|
||||
return -1;
|
||||
if (!(virDomainEventBlockThresholdClass =
|
||||
virClassNew(virDomainEventClass,
|
||||
"virDomainEventBlockThreshold",
|
||||
sizeof(virDomainEventBlockThreshold),
|
||||
virDomainEventBlockThresholdDispose)))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -600,6 +619,17 @@ virDomainEventMetadataChangeDispose(void *obj)
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
@ -1674,6 +1704,60 @@ virDomainEventMetadataChangeNewFromDom(virDomainPtr dom,
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
@ -1943,6 +2027,19 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
|
||||
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;
|
||||
}
|
||||
|
@ -244,6 +244,21 @@ virDomainEventMetadataChangeNewFromDom(virDomainPtr dom,
|
||||
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,
|
||||
|
@ -536,6 +536,8 @@ virDomainEventBlockJob2NewFromDom;
|
||||
virDomainEventBlockJob2NewFromObj;
|
||||
virDomainEventBlockJobNewFromDom;
|
||||
virDomainEventBlockJobNewFromObj;
|
||||
virDomainEventBlockThresholdNewFromDom;
|
||||
virDomainEventBlockThresholdNewFromObj;
|
||||
virDomainEventControlErrorNewFromDom;
|
||||
virDomainEventControlErrorNewFromObj;
|
||||
virDomainEventDeviceAddedNewFromDom;
|
||||
|
@ -395,6 +395,11 @@ remoteSecretBuildEventValueChanged(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
|
||||
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,
|
||||
@ -602,6 +607,10 @@ static virNetClientProgramEvent remoteEvents[] = {
|
||||
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
|
||||
@ -5577,6 +5586,30 @@ remoteSecretGetValue(virSecretPtr secret, size_t *value_size,
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
|
@ -3071,6 +3071,15 @@ struct remote_domain_event_block_job_2_msg {
|
||||
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;
|
||||
@ -6033,5 +6042,12 @@ enum remote_procedure {
|
||||
* @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
|
||||
|
||||
};
|
||||
|
@ -2516,6 +2516,14 @@ struct remote_domain_event_block_job_2_msg {
|
||||
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;
|
||||
@ -3217,4 +3225,5 @@ enum remote_procedure {
|
||||
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,
|
||||
};
|
||||
|
@ -12877,6 +12877,25 @@ virshEventMetadataChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
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), },
|
||||
@ -12924,6 +12943,8 @@ static vshEventCallback vshEventCallbacks[] = {
|
||||
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));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user