}
+static int
+myDomainEventMemoryDeviceSizeChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ unsigned long long size,
+ void *opaque G_GNUC_UNUSED)
+{
+ /* Casts to uint64_t to work around mingw not knowing %lld */
+ printf("%s EVENT: Domain %s(%d) memory device size change: "
+ "alias: '%s' new size %" PRIu64 "'\n",
+ __func__, virDomainGetName(dom), virDomainGetID(dom),
+ alias, (uint64_t)size);
+ return 0;
+}
+
+
static int
myDomainEventMigrationIterationCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFailureCallback),
+ DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE, myDomainEventMemoryDeviceSizeChangeCallback),
};
struct storagePoolEventData {
void *opaque);
+/**
+ * virConnectDomainEventMemoryDeviceSizeChangeCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @alias: memory device alias
+ * @size: new current size of memory device (in KiB)
+ * @opaque: application specified data
+ *
+ * The callback occurs when the guest acknowledges request to change size of
+ * memory device (so far only virtio-mem model supports this). The @size then
+ * reflects the new amount of guest visible memory (in kibibytes).
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE with
+ * virConnectDomainEventRegisterAny().
+ */
+typedef void (*virConnectDomainEventMemoryDeviceSizeChangeCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *alias,
+ unsigned long long size,
+ void *opaque);
+
+
/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
VIR_DOMAIN_EVENT_ID_METADATA_CHANGE = 23, /* virConnectDomainEventMetadataChangeCallback */
VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD = 24, /* virConnectDomainEventBlockThresholdCallback */
VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE = 25, /* virConnectDomainEventMemoryFailureCallback */
+ VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE = 26, /* virConnectDomainEventMemoryDeviceSizeChangeCallback */
# ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_ID_LAST
static virClass *virDomainEventMetadataChangeClass;
static virClass *virDomainEventBlockThresholdClass;
static virClass *virDomainEventMemoryFailureClass;
+static virClass *virDomainEventMemoryDeviceSizeChangeClass;
static void virDomainEventDispose(void *obj);
static void virDomainEventLifecycleDispose(void *obj);
static void virDomainEventMetadataChangeDispose(void *obj);
static void virDomainEventBlockThresholdDispose(void *obj);
static void virDomainEventMemoryFailureDispose(void *obj);
+static void virDomainEventMemoryDeviceSizeChangeDispose(void *obj);
static void
virDomainEventDispatchDefaultFunc(virConnectPtr conn,
};
typedef struct _virDomainEventMemoryFailure virDomainEventMemoryFailure;
+struct _virDomainEventMemoryDeviceSizeChange {
+ virDomainEvent parent;
+
+ char *alias;
+ unsigned long long size;
+};
+typedef struct _virDomainEventMemoryDeviceSizeChange virDomainEventMemoryDeviceSizeChange;
+typedef virDomainEventMemoryDeviceSizeChange *virDomainEventMemoryDeviceSizeChangePtr;
+
static int
virDomainEventsOnceInit(void)
{
return -1;
if (!VIR_CLASS_NEW(virDomainEventMemoryFailure, virDomainEventClass))
return -1;
+ if (!VIR_CLASS_NEW(virDomainEventMemoryDeviceSizeChange, virDomainEventClass))
+ return -1;
return 0;
}
VIR_DEBUG("obj=%p", event);
}
+static void
+virDomainEventMemoryDeviceSizeChangeDispose(void *obj)
+{
+ virDomainEventMemoryDeviceSizeChangePtr event = obj;
+ VIR_DEBUG("obj=%p", event);
+
+ g_free(event->alias);
+}
static void *
virDomainEventNew(virClass *klass,
recipient, action, flags);
}
+
+static virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNew(int id,
+ const char *name,
+ unsigned char *uuid,
+ const char *alias,
+ unsigned long long size)
+{
+ virDomainEventMemoryDeviceSizeChangePtr ev;
+
+ if (virDomainEventsInitialize() < 0)
+ return NULL;
+
+ if (!(ev = virDomainEventNew(virDomainEventMemoryDeviceSizeChangeClass,
+ VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE,
+ id, name, uuid)))
+ return NULL;
+
+ ev->alias = g_strdup(alias);
+ ev->size = size;
+
+ return (virObjectEvent *)ev;
+}
+
+
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromObj(virDomainObj *obj,
+ const char *alias,
+ unsigned long long size)
+{
+ return virDomainEventMemoryDeviceSizeChangeNew(obj->def->id,
+ obj->def->name,
+ obj->def->uuid,
+ alias,
+ size);
+}
+
+
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromDom(virDomainPtr dom,
+ const char *alias,
+ unsigned long long size)
+{
+ return virDomainEventMemoryDeviceSizeChangeNew(dom->id,
+ dom->name,
+ dom->uuid,
+ alias,
+ size);
+}
+
+
static void
virDomainEventDispatchDefaultFunc(virConnectPtr conn,
virObjectEvent *event,
goto cleanup;
}
+ case VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE:
+ {
+ virDomainEventMemoryDeviceSizeChangePtr memoryDeviceSizeChangeEvent;
+
+ memoryDeviceSizeChangeEvent = (virDomainEventMemoryDeviceSizeChangePtr)event;
+ ((virConnectDomainEventMemoryDeviceSizeChangeCallback)cb)(conn, dom,
+ memoryDeviceSizeChangeEvent->alias,
+ memoryDeviceSizeChangeEvent->size,
+ cbopaque);
+ goto cleanup;
+ }
+
case VIR_DOMAIN_EVENT_ID_LAST:
break;
}
int action,
unsigned int flags);
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromObj(virDomainObj *obj,
+ const char *alias,
+ unsigned long long size);
+
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromDom(virDomainPtr dom,
+ const char *alias,
+ unsigned long long size);
+
int
virDomainEventStateRegister(virConnectPtr conn,
virObjectEventState *state,
virDomainEventLifecycleNewFromDef;
virDomainEventLifecycleNewFromDom;
virDomainEventLifecycleNewFromObj;
+virDomainEventMemoryDeviceSizeChangeNewFromDom;
+virDomainEventMemoryDeviceSizeChangeNewFromObj;
virDomainEventMemoryFailureNewFromDom;
virDomainEventMemoryFailureNewFromObj;
virDomainEventMetadataChangeNewFromDom;
case QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE:
virObjectUnref(event->data);
break;
+ case QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE:
+ qemuMonitorMemoryDeviceSizeChangeFree(event->data);
+ break;
case QEMU_PROCESS_EVENT_PR_DISCONNECT:
case QEMU_PROCESS_EVENT_LAST:
break;
QEMU_PROCESS_EVENT_PR_DISCONNECT,
QEMU_PROCESS_EVENT_RDMA_GID_STATUS_CHANGED,
QEMU_PROCESS_EVENT_GUEST_CRASHLOADED,
+ QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
QEMU_PROCESS_EVENT_LAST
} qemuProcessEventType;
}
+static void
+processMemoryDeviceSizeChange(virQEMUDriver *driver,
+ virDomainObj *vm,
+ qemuMonitorMemoryDeviceSizeChange *info)
+{
+ virDomainMemoryDef *mem = NULL;
+ virObjectEvent *event = NULL;
+
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+ return;
+
+ if (!virDomainObjIsActive(vm)) {
+ VIR_DEBUG("Domain is not running");
+ goto endjob;
+ }
+
+ mem = virDomainMemoryFindByDeviceAlias(vm->def, info->devAlias);
+ if (!mem) {
+ VIR_DEBUG("Memory device '%s' not found", info->devAlias);
+ goto endjob;
+ }
+
+ mem->currentsize = VIR_DIV_UP(info->size, 1024);
+
+ event = virDomainEventMemoryDeviceSizeChangeNewFromObj(vm,
+ info->devAlias,
+ mem->currentsize);
+
+ endjob:
+ qemuDomainObjEndJob(driver, vm);
+ virObjectEventStateQueue(driver->domainEventState, event);
+}
+
+
static void qemuProcessEventHandler(void *data, void *opaque)
{
struct qemuProcessEvent *processEvent = data;
case QEMU_PROCESS_EVENT_GUEST_CRASHLOADED:
processGuestCrashloadedEvent(driver, vm);
break;
+ case QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE:
+ processMemoryDeviceSizeChange(driver, vm, processEvent->data);
+ break;
case QEMU_PROCESS_EVENT_LAST:
break;
}
}
+void
+qemuMonitorEmitMemoryDeviceSizeChange(qemuMonitor *mon,
+ const char *devAlias,
+ unsigned long long size)
+{
+ VIR_DEBUG("mon=%p, devAlias='%s', size=%llu", mon, devAlias, size);
+
+ QEMU_MONITOR_CALLBACK(mon, domainMemoryDeviceSizeChange, mon->vm, devAlias, size);
+}
+
+
void
qemuMonitorEmitMemoryFailure(qemuMonitor *mon,
qemuMonitorEventMemoryFailure *mfp)
}
+void
+qemuMonitorMemoryDeviceSizeChangeFree(qemuMonitorMemoryDeviceSizeChangePtr info)
+{
+ if (!info)
+ return;
+
+ g_free(info->devAlias);
+}
+
+
int
qemuMonitorSetWatchdogAction(qemuMonitor *mon,
const char *action)
};
+typedef struct _qemuMonitorMemoryDeviceSizeChange qemuMonitorMemoryDeviceSizeChange;
+typedef qemuMonitorMemoryDeviceSizeChange *qemuMonitorMemoryDeviceSizeChangePtr;
+struct _qemuMonitorMemoryDeviceSizeChange {
+ char *devAlias;
+ unsigned long long size;
+};
+
+
typedef enum {
QEMU_MONITOR_ACTION_SHUTDOWN_KEEP, /* do not change the current setting */
QEMU_MONITOR_ACTION_SHUTDOWN_POWEROFF,
char *qemuMonitorGuestPanicEventInfoFormatMsg(qemuMonitorEventPanicInfo *info);
void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfo *info);
void qemuMonitorEventRdmaGidStatusFree(qemuMonitorRdmaGidStatus *info);
+void qemuMonitorMemoryDeviceSizeChangeFree(qemuMonitorMemoryDeviceSizeChange *info);
typedef void (*qemuMonitorDestroyCallback)(qemuMonitor *mon,
virDomainObj *vm,
qemuMonitorEventMemoryFailure *mfp,
void *opaque);
+typedef int (*qemuMonitorDomainMemoryDeviceSizeChange)(qemuMonitor *mon,
+ virDomainObj *vm,
+ const char *alias,
+ unsigned long long size,
+ void *opaque);
+
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
struct _qemuMonitorCallbacks {
qemuMonitorEofNotifyCallback eofNotify;
qemuMonitorDomainRdmaGidStatusChangedCallback domainRdmaGidStatusChanged;
qemuMonitorDomainGuestCrashloadedCallback domainGuestCrashloaded;
qemuMonitorDomainMemoryFailureCallback domainMemoryFailure;
+ qemuMonitorDomainMemoryDeviceSizeChange domainMemoryDeviceSizeChange;
};
qemuMonitor *qemuMonitorOpen(virDomainObj *vm,
bool connected);
void qemuMonitorEmitSpiceMigrated(qemuMonitor *mon);
+void qemuMonitorEmitMemoryDeviceSizeChange(qemuMonitor *mon,
+ const char *devAlias,
+ unsigned long long size);
+
void qemuMonitorEmitMemoryFailure(qemuMonitor *mon,
qemuMonitorEventMemoryFailure *mfp);
static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon, virJSONValue *data);
static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon, virJSONValue *data);
static void qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon, virJSONValue *data);
+static void qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon, virJSONValue *data);
typedef struct {
const char *type;
{ "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, },
{ "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
{ "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, },
+ { "MEMORY_DEVICE_SIZE_CHANGE", qemuMonitorJSONHandleMemoryDeviceSizeChange, },
{ "MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure, },
{ "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
{ "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, },
}
+static void
+qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon,
+ virJSONValue *data)
+{
+ const char *name;
+ unsigned long long size;
+
+ if (!(name = virJSONValueObjectGetString(data, "id"))) {
+ VIR_WARN("missing device alias in MEMORY_DEVICE_SIZE_CHANGE event");
+ return;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "size", &size) < 0) {
+ VIR_WARN("missing new size for '%s' in MEMORY_DEVICE_SIZE_CHANGE event", name);
+ return;
+ }
+
+
+ qemuMonitorEmitMemoryDeviceSizeChange(mon, name, size);
+}
+
+
static void
qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon,
virJSONValue *data)
}
+static int
+qemuProcessHandleMemoryDeviceSizeChange(qemuMonitor *mon G_GNUC_UNUSED,
+ virDomainObj *vm,
+ const char *devAlias,
+ unsigned long long size,
+ void *opaque)
+{
+ virQEMUDriver *driver = opaque;
+ struct qemuProcessEvent *processEvent = NULL;
+ qemuMonitorMemoryDeviceSizeChange *info = NULL;
+ int ret = -1;
+
+ virObjectLock(vm);
+
+ VIR_DEBUG("Memory device '%s' changed size to '%llu' in domain '%s'",
+ devAlias, size, vm->def->name);
+
+ info = g_new0(qemuMonitorMemoryDeviceSizeChange, 1);
+ info->devAlias = g_strdup(devAlias);
+ info->size = size;
+
+ processEvent = g_new0(struct qemuProcessEvent, 1);
+ processEvent->eventType = QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE;
+ processEvent->vm = virObjectRef(vm);
+ processEvent->data = g_steal_pointer(&info);
+
+ if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
+ qemuProcessEventFree(processEvent);
+ virObjectUnref(vm);
+ goto cleanup;
+ }
+
+ processEvent = NULL;
+ ret = 0;
+ cleanup:
+ qemuProcessEventFree(processEvent);
+ virObjectUnlock(vm);
+ return ret;
+}
+
+
static qemuMonitorCallbacks monitorCallbacks = {
.eofNotify = qemuProcessHandleMonitorEOF,
.errorNotify = qemuProcessHandleMonitorError,
.domainRdmaGidStatusChanged = qemuProcessHandleRdmaGidStatusChanged,
.domainGuestCrashloaded = qemuProcessHandleGuestCrashloaded,
.domainMemoryFailure = qemuProcessHandleMemoryFailure,
+ .domainMemoryDeviceSizeChange = qemuProcessHandleMemoryDeviceSizeChange,
};
static void
}
+static int
+remoteRelayDomainEventMemoryDeviceSizeChange(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *alias,
+ unsigned long long size,
+ void *opaque)
+{
+ daemonClientEventCallback *callback = opaque;
+ remote_domain_event_memory_device_size_change_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ data.alias = g_strdup(alias);
+ data.size = size;
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_memory_device_size_change_msg,
+ &data);
+ return 0;
+}
+
+
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryFailure),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryDeviceSizeChange),
};
G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
void *evdata, void *opaque);
static void
+remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog,
+ virNetClient *client,
+ void *evdata, void *opaque);
+static void
remoteConnectNotifyEventConnectionClosed(virNetClientProgram *prog G_GNUC_UNUSED,
virNetClient *client G_GNUC_UNUSED,
void *evdata, void *opaque);
remoteDomainBuildEventMemoryFailure,
sizeof(remote_domain_event_memory_failure_msg),
(xdrproc_t)xdr_remote_domain_event_memory_failure_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
+ remoteDomainBuildEventMemoryDeviceSizeChange,
+ sizeof(remote_domain_event_memory_device_size_change_msg),
+ (xdrproc_t)xdr_remote_domain_event_memory_device_size_change_msg },
};
static void
}
+static void
+remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog G_GNUC_UNUSED,
+ virNetClient *client G_GNUC_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ remote_domain_event_memory_device_size_change_msg *msg = evdata;
+ struct private_data *priv = conn->privateData;
+ virDomainPtr dom;
+ virObjectEvent *event = NULL;
+
+ if (!(dom = get_nonnull_domain(conn, msg->dom)))
+ return;
+
+ event = virDomainEventMemoryDeviceSizeChangeNewFromDom(dom,
+ msg->alias,
+ msg->size);
+
+ virObjectUnref(dom);
+
+ virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackID);
+}
+
+
static int
remoteStreamSend(virStreamPtr st,
const char *data,
};
+struct remote_domain_event_memory_device_size_change_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_nonnull_string alias;
+ unsigned hyper size;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
* @acl: network:write
* @acl: network:start
*/
- REMOTE_PROC_NETWORK_CREATE_XML_FLAGS = 437
+ REMOTE_PROC_NETWORK_CREATE_XML_FLAGS = 437,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 438
};
int seconds;
u_int flags;
};
+struct remote_domain_event_memory_device_size_change_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_nonnull_string alias;
+ uint64_t size;
+};
enum remote_procedure {
REMOTE_PROC_CONNECT_OPEN = 1,
REMOTE_PROC_CONNECT_CLOSE = 2,
REMOTE_PROC_NODE_DEVICE_IS_PERSISTENT = 435,
REMOTE_PROC_NODE_DEVICE_IS_ACTIVE = 436,
REMOTE_PROC_NETWORK_CREATE_XML_FLAGS = 437,
+ REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 438,
};
}
+static void
+virshEventMemoryDeviceSizeChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ unsigned long long size,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf,
+ _("event 'memory-device-size-change' for domain '%s':\n"
+ "alias: %s\nsize: %llu\n"),
+ virDomainGetName(dom), alias, size);
+
+ virshEventPrint(opaque, &buf);
+}
+
+
virshDomainEventCallback virshDomainEventCallbacks[] = {
{ "lifecycle",
VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), },
{ "memory-failure",
VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryFailurePrint), },
+ { "memory-device-size-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryDeviceSizeChangePrint), },
};
G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST == G_N_ELEMENTS(virshDomainEventCallbacks));