I'm looking into implementing emitting events from the xen driver, and I've run into a bit of a snag that I would like to discuss I've attached an old version of my patch for reference. However - from past discussions, I know that there was a desire to keep the xen driver stateless. However, given the semantics of xenstore watches, and events, I'm not sure I can see a way to preserve this. Lets take the case of creating a new domain: XenStore gives us the functionaliity to put a watch on the special xenstore key @introduceDomain. However, when the watch fires - I see no mechanism of determining which domain has been introduced. The only mechanism I can find is to maintain a list of domains, and keep this up to date with events. So I'm wondering if anyone has any ideas, or if this will introduce unwanted, but necessary state into the driver? Ben
diff --git a/src/xen_unified.c b/src/xen_unified.c index dae68d3..eae0a8e 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -1294,6 +1294,28 @@ xenUnifiedNodeGetFreeMemory (virConnectPtr conn) return(0); } +static int xenUnifiedDomainEventRegister (virConnectPtr conn ATTRIBUTE_UNUSED, + void *callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + /* BTGXXX FIXME */ + return 0; +} + +int xenUnifiedDomainEventDeregister (virConnectPtr conn, + void *callback) +{ + /* BTGXXX FIXME */ + return 0; +} + +void xenUnifiedDomainEventDispatch (virDomainPtr dom, + virDomainEventType evt) +{ + /* BTGXXX FIXME */ + return; +} + /*----- Register with libvirt.c, and initialise Xen drivers. -----*/ #define HV_VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 + \ @@ -1359,6 +1381,9 @@ static virDriver xenUnifiedDriver = { .domainBlockPeek = xenUnifiedDomainBlockPeek, .nodeGetCellsFreeMemory = xenUnifiedNodeGetCellsFreeMemory, .getFreeMemory = xenUnifiedNodeGetFreeMemory, + .domainEventRegister = xenUnifiedDomainEventRegister, + .domainEventDeregister = xenUnifiedDomainEventDeregister, + .domainEventDispatch = xenUnifiedDomainEventDispatch, }; /** diff --git a/src/xen_unified.h b/src/xen_unified.h index c17b498..e4e7a59 100644 --- a/src/xen_unified.h +++ b/src/xen_unified.h @@ -12,6 +12,7 @@ #define __VIR_XEN_UNIFIED_H__ #include "internal.h" +#include "xs_internal.h" #include "capabilities.h" #ifndef HAVE_WINSOCK2_H @@ -110,6 +111,8 @@ struct _xenUnifiedPrivate { * xen_unified.c. */ int opened[XEN_UNIFIED_NR_DRIVERS]; + + xenStoreWatchListPtr xsWatchHead; }; typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr; diff --git a/src/xs_internal.c b/src/xs_internal.c index 316604a..31c9768 100644 --- a/src/xs_internal.c +++ b/src/xs_internal.c @@ -17,6 +17,7 @@ #include <fcntl.h> #include <sys/mman.h> #include <sys/ioctl.h> +#include <sys/poll.h> #include <stdint.h> @@ -28,6 +29,8 @@ #include "internal.h" #include "driver.h" +#include "memory.h" +#include "event.h" #include "xen_unified.h" #include "xs_internal.h" #include "xen_internal.h" /* for xenHypervisorCheckID */ @@ -40,6 +43,9 @@ #error "unsupported platform" #endif +#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt,__VA_ARGS__) +#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg) + #ifndef PROXY static char *xenStoreDomainGetOSType(virDomainPtr domain); @@ -319,6 +325,19 @@ xenStoreOpen(virConnectPtr conn, } return (-1); } + + /* Register for domain watch callbacks */ + xenStoreAddWatch(priv->xsWatchHead, "@introduceDomain", + "introduceDomain", xenStoreDomainIntroduced, priv); + xenStoreAddWatch(priv->xsWatchHead, "@releaseDomain", + "releaseDomain", xenStoreDomainReleased, priv); + /* Add an event handle */ + if (virEventAddHandle(xs_fileno(priv->xshandle), + POLLIN | POLLPRI, + xenStoreWatchEvent, + conn) < 0) { + return (-1); + } return (0); } @@ -344,6 +363,7 @@ xenStoreClose(virConnectPtr conn) if (priv->xshandle == NULL) return(-1); + xenStoreWatchListFree(priv->xsWatchHead); xs_daemon_close(priv->xshandle); return (0); } @@ -937,3 +957,147 @@ char *xenStoreDomainGetName(virConnectPtr conn, return xs_read(priv->xshandle, 0, prop, &len); } +void xenStoreWatchListFree(xenStoreWatchListPtr head) +{ + while (head) { + xenStoreWatchListPtr p = head->next; + VIR_FREE(head->path); + VIR_FREE(head->token); + VIR_FREE(head); + head = p; + } +} + +int xenStoreAddWatch(xenStoreWatchListPtr head, + const char *path, + const char *token, + xenStoreWatchCallback cb, + void *opaque) +{ + xenStoreWatchListPtr watch; + xenStoreWatchListPtr p = head; + + if (VIR_ALLOC(watch) < 0) + return -1; + watch->path = strdup(path); + watch->token = strdup(token); + watch->cb = cb; + watch->opaque = opaque; + + /* find end of list */ + while(p) p = p->next; + + DEBUG("Added xs watch %s %s", path, token); + p = watch; + return 0; +} + +int xenStoreRemoveWatch(xenStoreWatchListPtr head, + const char *path, + const char *token) +{ + xenStoreWatchListPtr p = head; + xenStoreWatchListPtr last = head; + while(p) { + if( STREQ(path, p->path) && + STREQ(token, p->token) ) { + if(last == p) + last = p->next; + else + last->next = p->next; + VIR_FREE(p->path); + VIR_FREE(p->token); + VIR_FREE(p); + DEBUG("Removed xs watch %s %s", path, token); + return 0; + } + last = p; + p = p->next; + } + return -1; +} + +xenStoreWatchListPtr xenStoreFindWatch(xenStoreWatchListPtr head, + const char *path, + const char *token) +{ + xenStoreWatchListPtr p = head; + while(p) { + if( p && + STREQ(path, p->path) && + STREQ(token, p->token) ) { + return p; + } + } + return NULL; +} + +void xenStoreWatchEvent(int fd ATTRIBUTE_UNUSED, + int events ATTRIBUTE_UNUSED, + void *data) +{ + char **event; + char *path; + char *token; + unsigned int stringCount; + xenStoreWatchListPtr sw; + + virConnectPtr conn = data; + xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData; + + if(!priv) return; + if(!priv->xshandle) return; + + event = xs_read_watch(priv->xshandle, &stringCount); + if (event == NULL) { + /* Nothing to process here */ + return; + } + + path = event[XS_WATCH_PATH]; + token = event[XS_WATCH_TOKEN]; + + sw = xenStoreFindWatch(priv->xsWatchHead, path, token); + if( sw ) { + DEBUG("%s Calling watch callback for %s %s", __FUNCTION__, sw->path, sw->token); + sw->cb(conn, path, token, sw->opaque); + } + VIR_FREE(event); +} + +static void +xenStoreCheckDomainExists(const void *payload, + const char *name ATTRIBUTE_UNUSED, + const void *data ATTRIBUTE_UNUSED) +{ + virDomainPtr dom = (virDomainPtr)payload; +} + +/* The domain callback for the @introduceDomain watch */ +int xenStoreDomainIntroduced(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + const char *token ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + /* TODO: Get dom somehow, and emit event + virConnectDispatchDomainEvent(conn, dom, VIR_DOMAIN_EVENT_STARTED); + */ + return 0; +} + +/* The domain callback for the @destroyDomain watch */ +int xenStoreDomainReleased(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + const char *token ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + /* + This will iterate over the domain list, and notice ones that + have potentially shut down of their own accord, and no longer + have a xenstore key. + + TODO: Find a public way of doing this + virHashForEach(conn->domains, xenStoreCheckDomainExists, NULL); + */ + return 0; +} diff --git a/src/xs_internal.h b/src/xs_internal.h index 6163ebc..39d59cb 100644 --- a/src/xs_internal.h +++ b/src/xs_internal.h @@ -53,4 +53,43 @@ char * xenStoreDomainGetDiskID(virConnectPtr conn, char * xenStoreDomainGetName(virConnectPtr conn, int id); +typedef int (*xenStoreWatchCallback)(virConnectPtr conn, + const char *path, + const char *token, + void *opaque); +typedef struct _xenStoreWatchList *xenStoreWatchListPtr; +struct _xenStoreWatchList { + char *path; + char *token; + xenStoreWatchCallback cb; + void *opaque; + struct _xenStoreWatchList *next; +}; + +void xenStoreWatchListFree(xenStoreWatchListPtr head); + +int xenStoreAddWatch(xenStoreWatchListPtr head, + const char *path, + const char *token, + xenStoreWatchCallback cb, + void *opaque); +int xenStoreRemoveWatch(xenStoreWatchListPtr head, + const char *path, + const char *token); +xenStoreWatchListPtr xenStoreFindWatch(xenStoreWatchListPtr head, + const char *path, + const char *token); +void xenStoreWatchEvent(int fd, int events, void *data); + +/* domain events */ +int xenStoreDomainIntroduced(virConnectPtr conn, + const char *path, + const char *token, + void *opaque); +int xenStoreDomainReleased(virConnectPtr conn, + const char *path, + const char *token, + void *opaque); + +int xenStoreDomainEventEmitted(virDomainEventType evt); #endif /* __VIR_XS_INTERNAL_H__ */
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list