libxl: Explicitly remove timeouts

I've noticed that libxl can invoke timeout reregister/modify hooks
after returning from libxl_ctx_free.  Explicitly remove the
timeouts before freeing the libxl ctx to avoid executing hooks on
stale objects.
This commit is contained in:
Jim Fehlig 2013-01-21 10:30:29 -07:00
parent 889ce7460c
commit ce33422d35
2 changed files with 77 additions and 4 deletions

View File

@ -79,6 +79,9 @@ struct _libxlDriverPrivate {
char *saveDir;
};
typedef struct _libxlEventHookInfo libxlEventHookInfo;
typedef libxlEventHookInfo *libxlEventHookInfoPtr;
typedef struct _libxlDomainObjPrivate libxlDomainObjPrivate;
typedef libxlDomainObjPrivate *libxlDomainObjPrivatePtr;
struct _libxlDomainObjPrivate {
@ -87,6 +90,9 @@ struct _libxlDomainObjPrivate {
/* per domain libxl ctx */
libxl_ctx *ctx;
libxl_evgen_domain_death *deathW;
/* list of libxl timeout registrations */
libxlEventHookInfoPtr timerRegistrations;
};
# define LIBXL_SAVE_MAGIC "libvirt-xml\n \0 \r"

View File

@ -59,10 +59,39 @@
/* Number of Xen scheduler parameters */
#define XEN_SCHED_CREDIT_NPARAM 2
/* Append an event registration to the list of registrations */
#define LIBXL_EV_REG_APPEND(head, add) \
do { \
libxlEventHookInfoPtr temp; \
if (head) { \
temp = head; \
while (temp->next) \
temp = temp->next; \
temp->next = add; \
} else { \
head = add; \
} \
} while (0)
/* Remove an event registration from the list of registrations */
#define LIBXL_EV_REG_REMOVE(head, del) \
do { \
libxlEventHookInfoPtr temp; \
if (head == del) { \
head = head->next; \
} else { \
temp = head; \
while (temp->next && temp->next != del) \
temp = temp->next; \
if (temp->next) { \
temp->next = del->next; \
} \
} \
} while (0)
/* Object used to store info related to libxl event registrations */
typedef struct _libxlEventHookInfo libxlEventHookInfo;
typedef libxlEventHookInfo *libxlEventHookInfoPtr;
struct _libxlEventHookInfo {
libxlEventHookInfoPtr next;
libxlDomainObjPrivatePtr priv;
void *xl_priv;
int id;
@ -229,7 +258,12 @@ libxlTimerCallback(int timer ATTRIBUTE_UNUSED, void *timer_info)
virObjectUnlock(p);
libxl_osevent_occurred_timeout(p->ctx, info->xl_priv);
virObjectLock(p);
virEventRemoveTimeout(info->id);
/*
* Timeout could have been freed while the lock was dropped.
* Only remove it from the list if it still exists.
*/
if (virEventRemoveTimeout(info->id) == 0)
LIBXL_EV_REG_REMOVE(p->timerRegistrations, info);
virObjectUnlock(p);
}
@ -275,6 +309,9 @@ libxlTimeoutRegisterEventHook(void *priv,
*/
virObjectRef(info->priv);
virObjectLock(info->priv);
LIBXL_EV_REG_APPEND(info->priv->timerRegistrations, info);
virObjectUnlock(info->priv);
info->xl_priv = xl_priv;
*hndp = info;
@ -314,10 +351,38 @@ libxlTimeoutDeregisterEventHook(void *priv ATTRIBUTE_UNUSED,
libxlDomainObjPrivatePtr p = info->priv;
virObjectLock(p);
virEventRemoveTimeout(info->id);
/*
* Only remove the timeout from the list if removal from the
* event loop is successful.
*/
if (virEventRemoveTimeout(info->id) == 0)
LIBXL_EV_REG_REMOVE(p->timerRegistrations, info);
virObjectUnlock(p);
}
static void
libxlRegisteredTimeoutsCleanup(libxlDomainObjPrivatePtr priv)
{
libxlEventHookInfoPtr info;
virObjectLock(priv);
info = priv->timerRegistrations;
while (info) {
/*
* libxl expects the event to be deregistered when calling
* libxl_osevent_occurred_timeout, but we dont want the event info
* destroyed. Disable the timeout and only remove it after returning
* from libxl.
*/
virEventUpdateTimeout(info->id, -1);
libxl_osevent_occurred_timeout(priv->ctx, info->xl_priv);
virEventRemoveTimeout(info->id);
info = info->next;
}
priv->timerRegistrations = NULL;
virObjectUnlock(priv);
}
static const libxl_osevent_hooks libxl_event_callbacks = {
.fd_register = libxlFDRegisterEventHook,
.fd_modify = libxlFDModifyEventHook,
@ -571,6 +636,8 @@ libxlVmCleanup(libxlDriverPrivatePtr driver,
vm->def->id = -1;
vm->newDef = NULL;
}
libxlRegisteredTimeoutsCleanup(priv);
}
/*