libxl: Handle domain death events in a thread

Similar to domain shutdown events, processing domain death events can be a
lengthy process and we don't want to block the event handler while the
operation completes. Move the death handling function to a thread.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Jim Fehlig 2021-11-24 11:36:55 -07:00
parent e4f7589a3e
commit b9a5faea49

View File

@ -613,12 +613,17 @@ libxlDomainShutdownThread(void *opaque)
} }
static void static void
libxlDomainHandleDeath(libxlDriverPrivate *driver, virDomainObj *vm) libxlDomainDeathThread(void *opaque)
{ {
struct libxlEventHandlerThreadInfo *death_info = opaque;
virDomainObj *vm = death_info->vm;
libxl_event *ev = death_info->event;
libxlDriverPrivate *driver = death_info->driver;
virObjectEvent *dom_event = NULL; virObjectEvent *dom_event = NULL;
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
return; goto cleanup;
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED); virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED);
dom_event = virDomainEventLifecycleNewFromObj(vm, dom_event = virDomainEventLifecycleNewFromObj(vm,
@ -629,6 +634,11 @@ libxlDomainHandleDeath(libxlDriverPrivate *driver, virDomainObj *vm)
virDomainObjListRemove(driver->domains, vm); virDomainObjListRemove(driver->domains, vm);
libxlDomainObjEndJob(driver, vm); libxlDomainObjEndJob(driver, vm);
virObjectEventStateQueue(driver->domainEventState, dom_event); virObjectEventStateQueue(driver->domainEventState, dom_event);
cleanup:
virDomainObjEndAPI(&vm);
libxl_event_free(cfg->ctx, ev);
VIR_FREE(death_info);
} }
@ -642,6 +652,9 @@ libxlDomainEventHandler(void *data, libxl_event *event)
libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason; libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason;
virDomainObj *vm = NULL; virDomainObj *vm = NULL;
g_autoptr(libxlDriverConfig) cfg = NULL; g_autoptr(libxlDriverConfig) cfg = NULL;
struct libxlEventHandlerThreadInfo *thread_info = NULL;
virThread thread;
g_autofree char *thread_name = NULL;
VIR_DEBUG("Received libxl event '%d' for domid '%d'", event->type, event->domid); VIR_DEBUG("Received libxl event '%d' for domid '%d'", event->type, event->domid);
@ -664,31 +677,27 @@ libxlDomainEventHandler(void *data, libxl_event *event)
goto cleanup; goto cleanup;
} }
/*
* Start event-specific threads to handle shutdown and death.
* They are potentially lengthy operations and we don't want to be
* blocking this event handler while they are in progress.
*/
if (event->type == LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) { if (event->type == LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) {
struct libxlEventHandlerThreadInfo *shutdown_info = NULL; thread_info = g_new0(struct libxlEventHandlerThreadInfo, 1);
virThread thread;
g_autofree char *name = NULL;
/* thread_info->driver = driver;
* Start a thread to handle shutdown. We don't want to be tying up thread_info->vm = vm;
* libxl's event machinery by doing a potentially lengthy shutdown. thread_info->event = (libxl_event *)event;
*/ thread_name = g_strdup_printf("shutdown-event-%d", event->domid);
shutdown_info = g_new0(struct libxlEventHandlerThreadInfo, 1);
shutdown_info->driver = driver;
shutdown_info->vm = vm;
shutdown_info->event = (libxl_event *)event;
name = g_strdup_printf("shutdown-event-%d", event->domid);
/* /*
* Cleanup will be handled by the shutdown thread. * Cleanup will be handled by the shutdown thread.
*/ */
if (virThreadCreateFull(&thread, false, libxlDomainShutdownThread, if (virThreadCreateFull(&thread, false, libxlDomainShutdownThread,
name, false, shutdown_info) < 0) { thread_name, false, thread_info) < 0) {
/* /*
* Not much we can do on error here except log it. * Not much we can do on error here except log it.
*/ */
VIR_ERROR(_("Failed to create thread to handle domain shutdown")); VIR_ERROR(_("Failed to create thread to handle domain shutdown"));
VIR_FREE(shutdown_info);
goto cleanup; goto cleanup;
} }
/* /*
@ -697,15 +706,33 @@ libxlDomainEventHandler(void *data, libxl_event *event)
*/ */
return; return;
} else if (event->type == LIBXL_EVENT_TYPE_DOMAIN_DEATH) { } else if (event->type == LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
thread_info = g_new0(struct libxlEventHandlerThreadInfo, 1);
thread_info->driver = driver;
thread_info->vm = vm;
thread_info->event = (libxl_event *)event;
thread_name = g_strdup_printf("death-event-%d", event->domid);
/* /*
* On death the domain is cleaned up from Xen's perspective. * Cleanup will be handled by the death thread.
* Cleanup on the libvirt side can be done synchronously.
*/ */
libxlDomainHandleDeath(driver, vm); if (virThreadCreateFull(&thread, false, libxlDomainDeathThread,
thread_name, false, thread_info) < 0) {
/*
* Not much we can do on error here except log it.
*/
VIR_ERROR(_("Failed to create thread to handle domain death"));
goto cleanup;
}
/*
* virDomainObjEndAPI is called in the death thread, where
* libxlEventHandlerThreadInfo and libxl_event are also freed.
*/
return;
} }
cleanup: cleanup:
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
VIR_FREE(thread_info);
cfg = libxlDriverConfigGet(driver); cfg = libxlDriverConfigGet(driver);
/* Cast away any const */ /* Cast away any const */
libxl_event_free(cfg->ctx, (libxl_event *)event); libxl_event_free(cfg->ctx, (libxl_event *)event);