Support domain lifecycle events for Xen (Ben Guthro & Daniel Berrange)

This commit is contained in:
Daniel P. Berrange 2008-11-25 10:44:52 +00:00
parent b2dbfefcf3
commit 1eeceaa649
17 changed files with 1404 additions and 70 deletions

View File

@ -1,3 +1,24 @@
Tue Nov 25 10:43:40 GMT 2008 Daniel P. Berrange <berrange@redhat.com>
Xen domain lifecycle events (Ben Guthro & Daniel Berrange)
* configure.in: Probe for inotify availability
* examples/domain-events/events-c/event-test.c: Default to NULL
connection URI to allow probing
* include/libvirt/virterror.h, src/virterror.c: Add error code
for xen inotify driver
* po/POTFILES.in: Add xen_inotify.c
* python/libvir.c: Add bogus const cast for python2.4 brokeness
* src/Makefile.am: Add xen_inotify.c
* src/util.c: Fix file descriptor leak in virRun
* src/xen_inotify.c, src/xen_inotify.h: Monitor /etc/xen and
/var/lib/xen/domains for new/old configs
* src/xen_unified.c, src/xen_unified.h: Wire in inotify driver
for events
* src/xm_internal.c, src/xm_internal.h: Refactor to allow inotify
monitoring of config files
* src/xs_internal.c, src/xs_internal.h: Use xenstore watch to
check for domain start/destroy events
Tue Nov 25 10:36:40 GMT 2008 Daniel P. Berrange <berrange@redhat.com>
* src/node_device_conf.c, src/node_device_conf.h,

View File

@ -147,6 +147,8 @@ fi
dnl Allow to build without Xen, QEMU/KVM, test or remote driver
AC_ARG_WITH([xen],
[ --with-xen add XEN support (on)],[],[with_xen=yes])
AC_ARG_WITH([xen-inotify],
[ --with-xen-inotify add XEN inotify support (on)],[],[with_xen_inotify=yes])
AC_ARG_WITH([qemu],
[ --with-qemu add QEMU/KVM support (on)],[],[with_qemu=yes])
AC_ARG_WITH([uml],
@ -334,6 +336,20 @@ AM_CONDITIONAL([WITH_XEN], [test "$with_xen" = "yes"])
AC_SUBST([XEN_CFLAGS])
AC_SUBST([XEN_LIBS])
dnl
dnl check for kernel headers required by xen_inotify
dnl
if test "$with_xen" != "yes"; then
with_xen_inotify=no
fi
if test "$with_xen_inotify" != "no"; then
AC_CHECK_HEADER([linux/inotify.h],[],[with_xen_inotify=no])
fi
if test "$with_xen_inotify" = "yes"; then
AC_DEFINE_UNQUOTED([WITH_XEN_INOTIFY], 1,[whether Xen inotify sub-driver is enabled])
fi
AM_CONDITIONAL([WITH_XEN_INOTIFY], [test "$with_xen_inotify" = "yes"])
dnl
dnl check for kernel headers required by src/bridge.c
dnl

View File

@ -308,7 +308,7 @@ int main(int argc, char **argv)
myEventRemoveTimeoutFunc);
virConnectPtr dconn = NULL;
dconn = virConnectOpen (argv[1] ? argv[1] : "qemu:///system");
dconn = virConnectOpen (argv[1] ? argv[1] : NULL);
if (!dconn) {
printf("error opening\n");
return -1;

View File

@ -60,6 +60,7 @@ typedef enum {
VIR_FROM_DOMAIN, /* Error from domain config */
VIR_FROM_UML, /* Error at the UML driver */
VIR_FROM_NODEDEV, /* Error from node device monitor */
VIR_FROM_XEN_INOTIFY, /* Error from xen inotify layer */
} virErrorDomain;

View File

@ -35,6 +35,7 @@ src/util.c
src/uuid.c
src/virsh.c
src/virterror.c
src/xen_inotify.c
src/xen_internal.c
src/xend_internal.c
src/xm_internal.c

View File

@ -1577,7 +1577,8 @@ getLibvirtModuleObject (void) {
return libvirt_module;
// PyImport_ImportModule returns a new reference
libvirt_module = PyImport_ImportModule("libvirt");
/* Bogus (char *) cast for RHEL-5 python API brokenness */
libvirt_module = PyImport_ImportModule((char *)"libvirt");
if(!libvirt_module) {
#if DEBUG_ERROR
printf("%s Error importing libvirt module\n", __FUNCTION__);

View File

@ -101,6 +101,9 @@ XEN_DRIVER_SOURCES = \
xend_internal.c xend_internal.h \
xm_internal.c xm_internal.h \
xs_internal.c xs_internal.h
if WITH_XEN_INOTIFY
XEN_DRIVER_SOURCES += xen_inotify.c xen_inotify.h
endif
LXC_DRIVER_SOURCES = \
lxc_conf.c lxc_conf.h \
@ -189,6 +192,8 @@ libvirt_driver_la_SOURCES = \
libvirt_driver_la_CFLAGS = $(XEN_CFLAGS)
libvirt_driver_la_LDFLAGS = $(XEN_LIBS)
libvirt_driver_la_CFLAGS = $(XEN_CFLAGS)
if WITH_TEST
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_test.la

View File

@ -613,6 +613,10 @@ virRun(virConnectPtr conn,
VIR_FREE(outbuf);
VIR_FREE(errbuf);
VIR_FREE(argv_str);
if (outfd != -1)
close(outfd);
if (errfd != -1)
close(errfd);
return ret;
}

View File

@ -262,6 +262,9 @@ virDefaultErrorFunc(virErrorPtr err)
case VIR_FROM_XENSTORE:
dom = "Xen Store ";
break;
case VIR_FROM_XEN_INOTIFY:
dom = "Xen Inotify ";
break;
case VIR_FROM_DOM:
dom = "Domain ";
break;

458
src/xen_inotify.c Normal file
View File

@ -0,0 +1,458 @@
/*
* xen_inofify.c: Xen notification of xml file activity in the
* following dirs:
* /etc/xen
* /var/lib/xend/domains
*
* Copyright (C) 2008 VirtualIron
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Ben Guthro
*/
#include <config.h>
#include <dirent.h>
#include <sys/inotify.h>
#include "virterror_internal.h"
#include "datatypes.h"
#include "driver.h"
#include "memory.h"
#include "event.h"
#include "xen_unified.h"
#include "conf.h"
#include "domain_conf.h"
#include "xen_inotify.h"
#include "xend_internal.h"
#include "logging.h"
#include "uuid.h"
#include "xm_internal.h" /* for xenXMDomainConfigParse */
#define virXenInotifyError(conn, code, fmt...) \
virReportErrorHelper(NULL, VIR_FROM_XEN_INOTIFY, code, __FILE__, \
__FUNCTION__, __LINE__, fmt)
#define LIBVIRTD_DOMAINS_DIR "/var/lib/xend/domains"
static const char *configDir = NULL;
static int useXenConfigCache = 0;
static xenUnifiedDomainInfoListPtr configInfoList = NULL;
struct xenUnifiedDriver xenInotifyDriver = {
xenInotifyOpen, /* open */
xenInotifyClose, /* close */
NULL, /* version */
NULL, /* hostname */
NULL, /* URI */
NULL, /* nodeGetInfo */
NULL, /* getCapabilities */
NULL, /* listDomains */
NULL, /* numOfDomains */
NULL, /* domainCreateLinux */
NULL, /* domainSuspend */
NULL, /* domainResume */
NULL, /* domainShutdown */
NULL, /* domainReboot */
NULL, /* domainDestroy */
NULL, /* domainGetOSType */
NULL, /* domainGetMaxMemory */
NULL, /* domainSetMaxMemory */
NULL, /* domainSetMemory */
NULL, /* domainGetInfo */
NULL, /* domainSave */
NULL, /* domainRestore */
NULL, /* domainCoreDump */
NULL, /* domainSetVcpus */
NULL, /* domainPinVcpu */
NULL, /* domainGetVcpus */
NULL, /* domainGetMaxVcpus */
NULL, /* listDefinedDomains */
NULL, /* numOfDefinedDomains */
NULL, /* domainCreate */
NULL, /* domainDefineXML */
NULL, /* domainUndefine */
NULL, /* domainAttachDevice */
NULL, /* domainDetachDevice */
NULL, /* domainGetAutostart */
NULL, /* domainSetAutostart */
NULL, /* domainGetSchedulerType */
NULL, /* domainGetSchedulerParameters */
NULL, /* domainSetSchedulerParameters */
};
static virDomainPtr
xenInotifyXenCacheLookup(virConnectPtr conn, const char *filename) {
xenXMConfCachePtr entry;
virDomainPtr dom;
if (!(entry = virHashLookup(xenXMGetConfigCache(), filename))) {
DEBUG("No config found for %s", filename);
return NULL;
}
if(!(dom = virGetDomain(conn, entry->def->name,
(unsigned char*)entry->def->uuid))) {
DEBUG0("Error getting dom from def");
return NULL;
}
return dom;
}
static virDomainPtr
xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename) {
int i;
virDomainPtr dom;
const char *uuid_str;
unsigned char uuid[VIR_UUID_BUFLEN];
/* xend is managing domains. we will get
* a filename in the manner:
* /var/lib/xend/domains/<uuid>/
*/
uuid_str = filename + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
if (virUUIDParse(uuid_str, uuid) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"parsing uuid %s", uuid_str);
return (NULL);
}
/* call directly into xend here, as driver may not yet
be set during open while we are building our
initial list of domains */
DEBUG("Looking for dom with uuid: %s", uuid_str);
if(!(dom = xenDaemonLookupByUUID(conn, uuid))) {
/* If we are here, the domain has gone away.
search for, and create a domain from the stored
list info */
for (i=0; i<configInfoList->count; i++) {
if (!memcmp(uuid, configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
if(!(dom = virGetDomain(conn, configInfoList->doms[i]->name,
configInfoList->doms[i]->uuid))) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"finding dom for %s", uuid_str);
return NULL;
}
DEBUG0("Found dom on list");
return dom;
}
}
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("finding dom on config list"));
return NULL;
}
/* succeeded too find domain by uuid */
return dom;
}
static virDomainPtr
xenInotifyDomainLookup(virConnectPtr conn, const char *filename) {
virDomainPtr dom;
virDomainInfo info;
dom = useXenConfigCache ? xenInotifyXenCacheLookup(conn, filename) :
xenInotifyXendDomainsDirLookup(conn, filename);
if(dom) {
if ( (useXenConfigCache ? xenXMDomainGetInfo(dom, &info) :
xenDaemonDomainGetInfo(dom, &info)) < 0)
dom->id = -1;
else
dom->id = (info.state == VIR_DOMAIN_SHUTOFF) ? -1 : dom->id;
return dom;
}
return NULL;
}
static int
xenInotifyXendDomainsDirRemoveEntry(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *fname) {
const char *uuidstr = fname + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
unsigned char uuid[VIR_UUID_BUFLEN];
int i;
if (virUUIDParse(uuidstr, uuid) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"parsing uuid %s", uuidstr);
return -1;
}
/* match and remove on uuid */
for (i=0; i<configInfoList->count; i++) {
if (!memcmp(uuid, configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
VIR_FREE(configInfoList->doms[i]->name);
VIR_FREE(configInfoList->doms[i]);
if (i < (configInfoList->count - 1))
memmove(configInfoList->doms + i,
configInfoList->doms + i + 1,
sizeof(*(configInfoList->doms)) *
(configInfoList->count - (i + 1)));
if (VIR_REALLOC_N(configInfoList->doms,
configInfoList->count - 1) < 0) {
; /* Failure to reduce memory allocation isn't fatal */
}
configInfoList->count--;
return 0;
}
}
return -1;
}
static int
xenInotifyXendDomainsDirAddEntry(virConnectPtr conn,
const char *fname) {
virDomainPtr dom = xenInotifyDomainLookup(conn, fname);
if(!dom) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error looking up domain"));
return -1;
}
if( xenUnifiedAddDomainInfo(configInfoList,
dom->id, dom->name, dom->uuid) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
virUnrefDomain(dom);
return -1;
}
virUnrefDomain(dom);
return 0;
}
static int
xenInotifyRemoveDomainConfigInfo(virConnectPtr conn,
const char *fname) {
return useXenConfigCache ? xenXMConfigCacheRemoveFile(conn, fname) :
xenInotifyXendDomainsDirRemoveEntry(conn, fname);
}
static int
xenInotifyAddDomainConfigInfo(virConnectPtr conn,
const char *fname) {
return useXenConfigCache ? xenXMConfigCacheAddFile(conn, fname) :
xenInotifyXendDomainsDirAddEntry(conn, fname);
}
static void
xenInotifyEvent(int watch ATTRIBUTE_UNUSED,
int fd,
int events ATTRIBUTE_UNUSED,
void *data)
{
char buf[1024];
char fname[1024];
struct inotify_event *e;
int got;
char *tmp, *name;
virConnectPtr conn = (virConnectPtr) data;
xenUnifiedPrivatePtr priv = NULL;
virDomainPtr dom = NULL;
DEBUG0("got inotify event");
if( conn && conn->privateData ) {
priv = conn->privateData;
} else {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("conn, or private data is NULL"));
return;
}
reread:
got = read(fd, buf, sizeof(buf));
if (got == -1) {
if (errno == EINTR)
goto reread;
return;
}
tmp = buf;
while (got) {
if (got < sizeof(struct inotify_event))
return; /* bad */
e = (struct inotify_event *)tmp;
tmp += sizeof(struct inotify_event);
got -= sizeof(struct inotify_event);
if (got < e->len)
return;
tmp += e->len;
got -= e->len;
name = (char *)&(e->name);
snprintf(fname, 1024, "%s/%s", configDir, name);
if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
if (!(dom = xenInotifyDomainLookup(conn, fname))) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("looking up dom"));
continue;
}
xenUnifiedDomainEventDispatch(conn->privateData, dom,
VIR_DOMAIN_EVENT_UNDEFINED,
VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
return;
}
} else if (e->mask & ( IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO) ) {
if (xenInotifyAddDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
return;
}
if (!(dom = xenInotifyDomainLookup(conn, fname))) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("looking up dom"));
continue;
}
xenUnifiedDomainEventDispatch(conn->privateData, dom,
VIR_DOMAIN_EVENT_DEFINED,
VIR_DOMAIN_EVENT_DEFINED_ADDED);
}
}
}
/**
* xenInotifyOpen:
* @conn: pointer to the connection block
* @name: URL for the target, NULL for local
* @flags: combination of virDrvOpenFlag(s)
*
* Connects and starts listening for inotify events
*
* Returns 0 or -1 in case of error.
*/
int
xenInotifyOpen(virConnectPtr conn ATTRIBUTE_UNUSED,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED)
{
DIR *dh;
struct dirent *ent;
char path[PATH_MAX];
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
if(priv->xendConfigVersion <= 2) {
/* /etc/xen */
configDir = xenXMGetConfigDir();
useXenConfigCache = 1;
} else {
/* /var/lib/xend/domains/<uuid>/config.sxp */
configDir = LIBVIRTD_DOMAINS_DIR;
useXenConfigCache = 0;
if ( VIR_ALLOC(configInfoList ) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("failed to allocate configInfoList"));
return -1;
}
/* populate initial list */
if (!(dh = opendir(configDir))) {
virXenInotifyError (NULL, VIR_ERR_INTERNAL_ERROR,
"%s", strerror(errno));
return -1;
}
while ((ent = readdir(dh))) {
if (STRPREFIX(ent->d_name, "."))
continue;
/* Build the full file path */
if ((strlen(configDir) + 1 + strlen(ent->d_name) + 1) > PATH_MAX)
continue;
strcpy(path, configDir);
strcat(path, "/");
strcat(path, ent->d_name);
if (xenInotifyAddDomainConfigInfo(conn, path) < 0 ) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config list"));
return -1;
}
}
}
if ((priv->inotifyFD = inotify_init()) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("initializing inotify"));
return -1;
}
DEBUG("Adding a watch on %s", configDir);
if (inotify_add_watch(priv->inotifyFD,
configDir,
IN_CREATE |
IN_CLOSE_WRITE | IN_DELETE |
IN_MOVED_TO | IN_MOVED_FROM) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"adding watch on %s", _(configDir));
return -1;
}
DEBUG0("Building initial config cache");
if (useXenConfigCache &&
xenXMConfigCacheRefresh (conn) < 0) {
DEBUG("Failed to enable XM config cache %s", conn->err.message);
return -1;
}
DEBUG0("Registering with event loop");
/* Add the handle for monitoring */
if ((priv->inotifyWatch = virEventAddHandle(priv->inotifyFD, VIR_EVENT_HANDLE_READABLE,
xenInotifyEvent, conn, NULL)) < 0) {
DEBUG0("Failed to add inotify handle, disabling events");
}
conn->refs++;
return 0;
}
/**
* xenInotifyClose:
* @conn: pointer to the connection block
*
* Close and stop listening for inotify events
*
* Returns 0 in case of success or -1 in case of error.
*/
int
xenInotifyClose(virConnectPtr conn)
{
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
if(configInfoList)
xenUnifiedDomainInfoListFree(configInfoList);
if (priv->inotifyWatch != -1)
virEventRemoveHandle(priv->inotifyWatch);
close(priv->inotifyFD);
virUnrefConnect(conn);
return 0;
}

31
src/xen_inotify.h Normal file
View File

@ -0,0 +1,31 @@
/*
* xen_inofify.h: Xen notification of xml files
*
* Copyright (C) 2008 VirtualIron
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Ben Guthro
*/
#ifndef __VIR_XEN_INOTIFY_H__
#define __VIR_XEN_INOTIFY_H__
#include "internal.h"
extern struct xenUnifiedDriver xenInotifyDriver;
int xenInotifyOpen (virConnectPtr conn,
virConnectAuthPtr auth,
int flags);
int xenInotifyClose (virConnectPtr conn);
#endif

View File

@ -37,6 +37,9 @@
#include "xend_internal.h"
#include "xs_internal.h"
#include "xm_internal.h"
#if WITH_XEN_INOTIFY
#include "xen_inotify.h"
#endif
#include "xml.h"
#include "util.h"
#include "memory.h"
@ -57,6 +60,9 @@ static struct xenUnifiedDriver *drivers[XEN_UNIFIED_NR_DRIVERS] = {
[XEN_UNIFIED_XEND_OFFSET] = &xenDaemonDriver,
[XEN_UNIFIED_XS_OFFSET] = &xenStoreDriver,
[XEN_UNIFIED_XM_OFFSET] = &xenXMDriver,
#if WITH_XEN_INOTIFY
[XEN_UNIFIED_INOTIFY_OFFSET] = &xenInotifyDriver,
#endif
};
#define xenUnifiedError(conn, code, fmt...) \
@ -223,6 +229,7 @@ xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags)
{
int i, ret = VIR_DRV_OPEN_DECLINED;
xenUnifiedPrivatePtr priv;
virDomainEventCallbackListPtr cbList;
if (conn->uri == NULL) {
if (!xenUnifiedProbe())
@ -260,6 +267,13 @@ xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags)
}
conn->privateData = priv;
/* Allocate callback list */
if (VIR_ALLOC(cbList) < 0) {
xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "allocating callback list");
return VIR_DRV_OPEN_ERROR;
}
priv->domainEventCallbacks = cbList;
priv->handle = -1;
priv->xendConfigVersion = -1;
priv->type = -1;
@ -333,6 +347,15 @@ xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags)
goto fail;
}
#if WITH_XEN_INOTIFY
DEBUG0("Trying Xen inotify sub-driver");
if (drivers[XEN_UNIFIED_INOTIFY_OFFSET]->open(conn, auth, flags) ==
VIR_DRV_OPEN_SUCCESS) {
DEBUG0("Activated Xen inotify sub-driver");
priv->opened[XEN_UNIFIED_INOTIFY_OFFSET] = 1;
}
#endif
return VIR_DRV_OPEN_SUCCESS;
fail:
@ -357,6 +380,8 @@ xenUnifiedClose (virConnectPtr conn)
int i;
virCapabilitiesFree(priv->caps);
virDomainEventCallbackListFree(priv->domainEventCallbacks);
for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
if (priv->opened[i] && drivers[i]->close)
(void) drivers[i]->close (conn);
@ -1292,6 +1317,40 @@ xenUnifiedNodeGetFreeMemory (virConnectPtr conn)
return(0);
}
static int
xenUnifiedDomainEventRegister (virConnectPtr conn,
void *callback,
void *opaque,
void (*freefunc)(void *))
{
GET_PRIVATE (conn);
if (priv->xsWatch == -1) {
xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
}
conn->refs++;
return virDomainEventCallbackListAdd(conn, priv->domainEventCallbacks,
callback, opaque, freefunc);
}
static int
xenUnifiedDomainEventDeregister (virConnectPtr conn,
void *callback)
{
int ret;
GET_PRIVATE (conn);
if (priv->xsWatch == -1) {
xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
}
ret = virDomainEventCallbackListRemove(conn, priv->domainEventCallbacks,
callback);
virUnrefConnect(conn);
return ret;
}
/*----- Register with libvirt.c, and initialise Xen drivers. -----*/
#define HV_VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 + \
@ -1356,6 +1415,8 @@ static virDriver xenUnifiedDriver = {
.domainBlockPeek = xenUnifiedDomainBlockPeek,
.nodeGetCellsFreeMemory = xenUnifiedNodeGetCellsFreeMemory,
.getFreeMemory = xenUnifiedNodeGetFreeMemory,
.domainEventRegister = xenUnifiedDomainEventRegister,
.domainEventDeregister = xenUnifiedDomainEventDeregister,
};
/**
@ -1375,3 +1436,139 @@ xenRegister (void)
return virRegisterDriver (&xenUnifiedDriver);
}
/**
* xenUnifiedDomainInfoListFree:
*
* Free the Domain Info List
*/
void
xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr list)
{
int i;
for (i=0; i<list->count; i++) {
VIR_FREE(list->doms[i]->name);
VIR_FREE(list->doms[i]);
}
VIR_FREE(list);
}
/**
* xenUnifiedAddDomainInfo:
*
* Add name and uuid to the domain info list
*
* Returns: 0 on success, -1 on failure
*/
int
xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr list,
int id, char *name,
unsigned char *uuid)
{
xenUnifiedDomainInfoPtr info;
int n;
/* check if we already have this callback on our list */
for (n=0; n < list->count; n++) {
if (STREQ(list->doms[n]->name, name) &&
!memcmp(list->doms[n]->uuid, uuid, VIR_UUID_BUFLEN)) {
DEBUG0("WARNING: dom already tracked");
return -1;
}
}
if (VIR_ALLOC(info) < 0)
goto memory_error;
if (!(info->name = strdup(name)))
goto memory_error;
memcpy(info->uuid, uuid, VIR_UUID_BUFLEN);
info->id = id;
/* Make space on list */
n = list->count;
if (VIR_REALLOC_N(list->doms, n + 1) < 0) {
goto memory_error;
}
list->doms[n] = info;
list->count++;
return 0;
memory_error:
xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "allocating domain info");
if (info)
VIR_FREE(info->name);
VIR_FREE(info);
return -1;
}
/**
* xenUnifiedRemoveDomainInfo:
*
* Removes name and uuid to the domain info list
*
* Returns: 0 on success, -1 on failure
*/
int
xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr list,
int id, char *name,
unsigned char *uuid)
{
int i;
for (i = 0 ; i < list->count ; i++) {
if( list->doms[i]->id == id &&
STREQ(list->doms[i]->name, name) &&
!memcmp(list->doms[i]->uuid, uuid, VIR_UUID_BUFLEN)) {
VIR_FREE(list->doms[i]->name);
VIR_FREE(list->doms[i]);
if (i < (list->count - 1))
memmove(list->doms + i,
list->doms + i + 1,
sizeof(*(list->doms)) *
(list->count - (i + 1)));
if (VIR_REALLOC_N(list->doms,
list->count - 1) < 0) {
; /* Failure to reduce memory allocation isn't fatal */
}
list->count--;
return 0;
}
}
return -1;
}
/**
* xenUnifiedDomainEventDispatch:
*
* Dispatch domain events to registered callbacks
*
*/
void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
virDomainPtr dom,
int event,
int detail)
{
int i;
virDomainEventCallbackListPtr cbList;
if(!priv) return;
cbList = priv->domainEventCallbacks;
if(!cbList) return;
for(i=0 ; i < cbList->count ; i++) {
if(cbList->callbacks[i] && cbList->callbacks[i]->cb) {
if (dom) {
DEBUG("Dispatching callback %p %p event %d",
cbList->callbacks[i],
cbList->callbacks[i]->cb, event);
cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
dom, event, detail,
cbList->callbacks[i]->opaque);
}
}
}
}

View File

@ -14,6 +14,12 @@
#include "internal.h"
#include "capabilities.h"
#include "driver.h"
#include "domain_conf.h"
#include "xs_internal.h"
#if WITH_XEN_INOTIFY
#include "xen_inotify.h"
#endif
#include "domain_event.h"
#ifndef HAVE_WINSOCK2_H
#include <sys/un.h>
@ -29,7 +35,13 @@ extern int xenRegister (void);
#define XEN_UNIFIED_XEND_OFFSET 2
#define XEN_UNIFIED_XS_OFFSET 3
#define XEN_UNIFIED_XM_OFFSET 4
#if WITH_XEN_INOTIFY
#define XEN_UNIFIED_INOTIFY_OFFSET 5
#define XEN_UNIFIED_NR_DRIVERS 6
#else
#define XEN_UNIFIED_NR_DRIVERS 5
#endif
#define MIN_XEN_GUEST_SIZE 64 /* 64 megabytes */
@ -85,6 +97,33 @@ struct xenUnifiedDriver {
virDrvDomainSetSchedulerParameters domainSetSchedulerParameters;
};
typedef struct xenXMConfCache *xenXMConfCachePtr;
typedef struct xenXMConfCache {
time_t refreshedAt;
char filename[PATH_MAX];
virDomainDefPtr def;
} xenXMConfCache;
/* xenUnifiedDomainInfoPtr:
* The minimal state we have about active domains
* This is the minmal info necessary to still get a
* virDomainPtr when the domain goes away
*/
struct _xenUnifiedDomainInfo {
int id;
char *name;
unsigned char uuid[VIR_UUID_BUFLEN];
};
typedef struct _xenUnifiedDomainInfo xenUnifiedDomainInfo;
typedef xenUnifiedDomainInfo *xenUnifiedDomainInfoPtr;
struct _xenUnifiedDomainInfoList {
unsigned int count;
xenUnifiedDomainInfoPtr *doms;
};
typedef struct _xenUnifiedDomainInfoList xenUnifiedDomainInfoList;
typedef xenUnifiedDomainInfoList *xenUnifiedDomainInfoListPtr;
/* xenUnifiedPrivatePtr:
*
* Per-connection private data, stored in conn->privateData. All Xen
@ -113,6 +152,19 @@ struct _xenUnifiedPrivate {
* xen_unified.c.
*/
int opened[XEN_UNIFIED_NR_DRIVERS];
/* A list of xenstore watches */
xenStoreWatchListPtr xsWatchList;
int xsWatch;
/* An list of callbacks */
virDomainEventCallbackListPtr domainEventCallbacks;
#if WITH_XEN_INOTIFY
/* The inotify fd */
int inotifyFD;
int inotifyWatch;
#endif
};
typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr;
@ -122,4 +174,15 @@ int xenNbCells(virConnectPtr conn);
int xenNbCpus(virConnectPtr conn);
char *xenDomainUsedCpus(virDomainPtr dom);
void xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr info);
int xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr info,
int id, char *name,
unsigned char *uuid);
int xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
int id, char *name,
unsigned char *uuid);
void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
virDomainPtr dom,
int event,
int detail);
#endif /* __VIR_XEN_UNIFIED_H__ */

View File

@ -45,6 +45,8 @@
#include "uuid.h"
#include "util.h"
#include "memory.h"
#include "logging.h"
/* The true Xen limit varies but so far is always way
less than 1024, which is the Linux kernel limit according
@ -54,13 +56,6 @@
static int xenXMConfigSetString(virConfPtr conf, const char *setting,
const char *str);
typedef struct xenXMConfCache *xenXMConfCachePtr;
typedef struct xenXMConfCache {
time_t refreshedAt;
char filename[PATH_MAX];
virDomainDefPtr def;
} xenXMConfCache;
static char configDir[PATH_MAX];
/* Config file name to config object */
static virHashTablePtr configCache = NULL;
@ -124,6 +119,14 @@ struct xenUnifiedDriver xenXMDriver = {
NULL, /* domainSetSchedulerParameters */
};
virHashTablePtr xenXMGetConfigCache (void) {
return configCache;
}
char *xenXMGetConfigDir (void) {
return configDir;
}
#define xenXMError(conn, code, fmt...) \
virReportErrorHelper(conn, VIR_FROM_XENXM, code, __FILE__, \
__FUNCTION__, __LINE__, fmt)
@ -371,13 +374,121 @@ xenXMConfigSaveFile(virConnectPtr conn, const char *filename, virDomainDefPtr de
return ret;
}
int
xenXMConfigCacheRemoveFile(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *filename)
{
xenXMConfCachePtr entry;
entry = virHashLookup(configCache, filename);
if (!entry) {
DEBUG("No config entry for %s", filename);
return 0;
}
virHashRemoveEntry(nameConfigMap, entry->def->name, NULL);
virHashRemoveEntry(configCache, filename, xenXMConfigFree);
DEBUG("Removed %s %s", entry->def->name, filename);
return 0;
}
int
xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
{
xenXMConfCachePtr entry;
struct stat st;
int newborn = 0;
time_t now = time(NULL);
DEBUG("Adding file %s", filename);
/* Get modified time */
if ((stat(filename, &st) < 0)) {
xenXMError (conn, VIR_ERR_INTERNAL_ERROR,
"cannot stat %s: %s", filename, strerror(errno));
return -1;
}
/* Ignore zero length files, because inotify fires before
any content has actually been created */
if (st.st_size == 0) {
DEBUG("Ignoring zero length file %s", filename);
return -1;
}
/* If we already have a matching entry and it is not
modified, then carry on to next one*/
if ((entry = virHashLookup(configCache, filename))) {
char *nameowner;
if (entry->refreshedAt >= st.st_mtime) {
entry->refreshedAt = now;
/* return success if up-to-date */
return 0;
}
/* If we currently own the name, then release it and
re-acquire it later - just in case it was renamed */
nameowner = (char *)virHashLookup(nameConfigMap, entry->def->name);
if (nameowner && STREQ(nameowner, filename)) {
virHashRemoveEntry(nameConfigMap, entry->def->name, NULL);
}
/* Clear existing config entry which needs refresh */
virDomainDefFree(entry->def);
entry->def = NULL;
} else { /* Completely new entry */
newborn = 1;
if (VIR_ALLOC(entry) < 0) {
xenXMError (conn, VIR_ERR_NO_MEMORY, "%s", strerror(errno));
return -1;
}
memcpy(entry->filename, filename, PATH_MAX);
}
entry->refreshedAt = now;
if (!(entry->def = xenXMConfigReadFile(conn, entry->filename))) {
DEBUG("Failed to read %s", entry->filename);
if (!newborn)
virHashRemoveEntry(configCache, filename, NULL);
VIR_FREE(entry);
return -1;
}
/* If its a completely new entry, it must be stuck into
the cache (refresh'd entries are already registered) */
if (newborn) {
if (virHashAddEntry(configCache, entry->filename, entry) < 0) {
virDomainDefFree(entry->def);
VIR_FREE(entry);
xenXMError (conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("xenXMConfigCacheRefresh: virHashAddEntry"));
return -1;
}
}
/* See if we need to map this config file in as the primary owner
* of the domain in question
*/
if (!virHashLookup(nameConfigMap, entry->def->name)) {
if (virHashAddEntry(nameConfigMap, entry->def->name, entry->filename) < 0) {
virHashRemoveEntry(configCache, filename, NULL);
virDomainDefFree(entry->def);
VIR_FREE(entry);
}
}
DEBUG("Added config %s %s", entry->def->name, filename);
return 0;
}
/* This method is called by various methods to scan /etc/xen
(or whatever directory was set by LIBVIRT_XM_CONFIG_DIR
environment variable) and process any domain configs. It
has rate-limited so never rescans more frequently than
once every X seconds */
static int xenXMConfigCacheRefresh (virConnectPtr conn) {
int xenXMConfigCacheRefresh (virConnectPtr conn) {
DIR *dh;
struct dirent *ent;
time_t now = time(NULL);
@ -401,9 +512,7 @@ static int xenXMConfigCacheRefresh (virConnectPtr conn) {
}
while ((ent = readdir(dh))) {
xenXMConfCachePtr entry;
struct stat st;
int newborn = 0;
char path[PATH_MAX];
/*
@ -447,62 +556,8 @@ static int xenXMConfigCacheRefresh (virConnectPtr conn) {
/* If we already have a matching entry and it is not
modified, then carry on to next one*/
if ((entry = virHashLookup(configCache, path))) {
char *nameowner;
if (entry->refreshedAt >= st.st_mtime) {
entry->refreshedAt = now;
continue;
}
/* If we currently own the name, then release it and
re-acquire it later - just in case it was renamed */
nameowner = (char *)virHashLookup(nameConfigMap, entry->def->name);
if (nameowner && STREQ(nameowner, path)) {
virHashRemoveEntry(nameConfigMap, entry->def->name, NULL);
}
/* Clear existing config entry which needs refresh */
virDomainDefFree(entry->def);
entry->def = NULL;
} else { /* Completely new entry */
newborn = 1;
if (VIR_ALLOC(entry) < 0) {
xenXMError (conn, VIR_ERR_NO_MEMORY, "%s", strerror(errno));
goto cleanup;
}
memcpy(entry->filename, path, PATH_MAX);
}
entry->refreshedAt = now;
if (!(entry->def = xenXMConfigReadFile(conn, entry->filename))) {
if (!newborn)
virHashRemoveEntry(configCache, path, NULL);
VIR_FREE(entry);
continue;
}
/* If its a completely new entry, it must be stuck into
the cache (refresh'd entries are already registered) */
if (newborn) {
if (virHashAddEntry(configCache, entry->filename, entry) < 0) {
virDomainDefFree(entry->def);
VIR_FREE(entry);
xenXMError (conn, VIR_ERR_INTERNAL_ERROR,
"%s", _("xenXMConfigCacheRefresh: virHashAddEntry"));
goto cleanup;
}
}
/* See if we need to map this config file in as the primary owner
* of the domain in question
*/
if (!virHashLookup(nameConfigMap, entry->def->name)) {
if (virHashAddEntry(nameConfigMap, entry->def->name, entry->filename) < 0) {
virHashRemoveEntry(configCache, ent->d_name, NULL);
virDomainDefFree(entry->def);
VIR_FREE(entry);
}
if (xenXMConfigCacheAddFile(conn, path) < 0) {
/* Ignoring errors, since alot of stuff goes wrong in /etc/xen */
}
}
@ -513,7 +568,6 @@ static int xenXMConfigCacheRefresh (virConnectPtr conn) {
virHashRemoveSet(configCache, xenXMConfigReaper, xenXMConfigFree, (const void*) &now);
ret = 0;
cleanup:
if (dh)
closedir(dh);
@ -1503,8 +1557,10 @@ virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname) {
return (NULL);
}
#ifndef WITH_XEN_INOTIFY
if (xenXMConfigCacheRefresh (conn) < 0)
return (NULL);
#endif
if (!(filename = virHashLookup(nameConfigMap, domname)))
return (NULL);
@ -1555,8 +1611,10 @@ virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
return (NULL);
}
#ifndef WITH_XEN_INOTIFY
if (xenXMConfigCacheRefresh (conn) < 0)
return (NULL);
#endif
if (!(entry = virHashSearch(configCache, xenXMDomainSearchForUUID, (const void *)uuid))) {
return (NULL);
@ -2208,8 +2266,10 @@ virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml) {
if (conn->flags & VIR_CONNECT_RO)
return (NULL);
#ifndef WITH_XEN_INOTIFY
if (xenXMConfigCacheRefresh (conn) < 0)
return (NULL);
#endif
if (!(def = virDomainDefParseString(conn, priv->caps, xml)))
return (NULL);
@ -2376,8 +2436,10 @@ int xenXMListDefinedDomains(virConnectPtr conn, char **const names, int maxnames
return (-1);
}
#ifndef WITH_XEN_INOTIFY
if (xenXMConfigCacheRefresh (conn) < 0)
return (-1);
#endif
if (maxnames > virHashSize(configCache))
maxnames = virHashSize(configCache);
@ -2401,8 +2463,10 @@ int xenXMNumOfDefinedDomains(virConnectPtr conn) {
return (-1);
}
#ifndef WITH_XEN_INOTIFY
if (xenXMConfigCacheRefresh (conn) < 0)
return (-1);
#endif
return virHashSize(nameConfigMap);
}

View File

@ -32,6 +32,12 @@
extern struct xenUnifiedDriver xenXMDriver;
int xenXMInit (void);
virHashTablePtr xenXMGetConfigCache(void);
char *xenXMGetConfigDir(void);
int xenXMConfigCacheRefresh (virConnectPtr conn);
int xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename);
int xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename);
int xenXMOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
int xenXMClose(virConnectPtr conn);
const char *xenXMGetType(virConnectPtr conn);

View File

@ -29,6 +29,10 @@
#include "virterror_internal.h"
#include "datatypes.h"
#include "driver.h"
#include "memory.h"
#include "event.h"
#include "logging.h"
#include "uuid.h"
#include "xen_unified.h"
#include "xs_internal.h"
#include "xen_internal.h" /* for xenHypervisorCheckID */
@ -42,6 +46,9 @@
#endif
#ifndef PROXY
/* A list of active domain name/uuids */
static xenUnifiedDomainInfoListPtr activeDomainList = NULL;
static char *xenStoreDomainGetOSType(virDomainPtr domain);
struct xenUnifiedDriver xenStoreDriver = {
@ -302,7 +309,52 @@ xenStoreOpen(virConnectPtr conn,
}
return (-1);
}
return (0);
#ifndef PROXY
/* Init activeDomainList */
if ( VIR_ALLOC(activeDomainList) < 0) {
virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("failed to allocate activeDomainList"));
return -1;
}
/* Init watch list before filling in domInfoList,
so we can know if it is the first time through
when the callback fires */
if ( VIR_ALLOC(priv->xsWatchList) < 0 ) {
virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("failed to allocate xsWatchList"));
return -1;
}
/* This will get called once at start */
if ( xenStoreAddWatch(conn, "@releaseDomain",
"releaseDomain", xenStoreDomainReleased, priv) < 0 )
{
virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("adding watch @releaseDomain"));
return -1;
}
/* The initial call of this will fill domInfoList */
if( xenStoreAddWatch(conn, "@introduceDomain",
"introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
{
virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("adding watch @introduceDomain"));
return -1;
}
/* Add an event handle */
if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle),
VIR_EVENT_HANDLE_READABLE,
xenStoreWatchEvent,
conn,
NULL)) < 0)
DEBUG0("Failed to add event handle, disabling events\n");
#endif //PROXY
return 0;
}
/**
@ -324,10 +376,29 @@ xenStoreClose(virConnectPtr conn)
}
priv = (xenUnifiedPrivatePtr) conn->privateData;
if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
DEBUG0("Warning, could not remove @introduceDomain watch");
/* not fatal */
}
if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
DEBUG0("Warning, could not remove @releaseDomain watch");
/* not fatal */
}
xenStoreWatchListFree(priv->xsWatchList);
#ifndef PROXY
xenUnifiedDomainInfoListFree(activeDomainList);
#endif
if (priv->xshandle == NULL)
return(-1);
if (priv->xsWatch != -1)
virEventRemoveHandle(priv->xsWatch);
xs_daemon_close(priv->xshandle);
priv->xshandle = NULL;
return (0);
}
@ -920,3 +991,343 @@ char *xenStoreDomainGetName(virConnectPtr conn,
return xs_read(priv->xshandle, 0, prop, &len);
}
#ifndef PROXY
int xenStoreDomainGetUUID(virConnectPtr conn,
int id,
unsigned char *uuid) {
char prop[200];
xenUnifiedPrivatePtr priv;
unsigned int len;
char *uuidstr;
int ret = 0;
priv = (xenUnifiedPrivatePtr) conn->privateData;
if (priv->xshandle == NULL)
return -1;
snprintf(prop, 199, "/local/domain/%d/vm", id);
prop[199] = 0;
// This will return something like
// /vm/00000000-0000-0000-0000-000000000000
uuidstr = xs_read(priv->xshandle, 0, prop, &len);
// remove "/vm/"
ret = virUUIDParse(uuidstr + 4, uuid);
VIR_FREE(uuidstr);
return ret;
}
#endif //PROXY
void xenStoreWatchListFree(xenStoreWatchListPtr list)
{
int i;
for (i=0; i<list->count; i++) {
VIR_FREE(list->watches[i]->path);
VIR_FREE(list->watches[i]->token);
VIR_FREE(list->watches[i]);
}
VIR_FREE(list);
}
int xenStoreAddWatch(virConnectPtr conn,
const char *path,
const char *token,
xenStoreWatchCallback cb,
void *opaque)
{
xenStoreWatchPtr watch;
int n;
xenStoreWatchListPtr list;
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
if (priv->xshandle == NULL)
return -1;
list = priv->xsWatchList;
if(!list)
return -1;
/* check if we already have this callback on our list */
for (n=0; n < list->count; n++) {
if( STREQ(list->watches[n]->path, path) &&
STREQ(list->watches[n]->token, token)) {
virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("watch already tracked"));
return -1;
}
}
if (VIR_ALLOC(watch) < 0)
return -1;
watch->path = strdup(path);
watch->token = strdup(token);
watch->cb = cb;
watch->opaque = opaque;
/* Make space on list */
n = list->count;
if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("reallocating list"));
VIR_FREE(watch);
return -1;
}
list->watches[n] = watch;
list->count++;
conn->refs++;
return xs_watch(priv->xshandle, watch->path, watch->token);
}
int xenStoreRemoveWatch(virConnectPtr conn,
const char *path,
const char *token)
{
int i;
xenStoreWatchListPtr list;
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
if (priv->xshandle == NULL)
return -1;
list = priv->xsWatchList;
if(!list)
return -1;
for (i = 0 ; i < list->count ; i++) {
if( STREQ(list->watches[i]->path, path) &&
STREQ(list->watches[i]->token, token)) {
if (!xs_unwatch(priv->xshandle,
list->watches[i]->path,
list->watches[i]->path))
{
DEBUG0("WARNING: Could not remove watch");
/* Not fatal, continue */
}
VIR_FREE(list->watches[i]->path);
VIR_FREE(list->watches[i]->token);
VIR_FREE(list->watches[i]);
if (i < (list->count - 1))
memmove(list->watches + i,
list->watches + i + 1,
sizeof(*(list->watches)) *
(list->count - (i + 1)));
if (VIR_REALLOC_N(list->watches,
list->count - 1) < 0) {
; /* Failure to reduce memory allocation isn't fatal */
}
list->count--;
#ifndef PROXY
virUnrefConnect(conn);
#endif
return 0;
}
}
return -1;
}
xenStoreWatchPtr xenStoreFindWatch(xenStoreWatchListPtr list,
const char *path,
const char *token)
{
int i;
for (i = 0 ; i < list->count ; i++)
if( STREQ(path, list->watches[i]->path) &&
STREQ(token, list->watches[i]->token) )
return list->watches[i];
return NULL;
}
void xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
int fd ATTRIBUTE_UNUSED,
int events ATTRIBUTE_UNUSED,
void *data)
{
char **event;
char *path;
char *token;
unsigned int stringCount;
xenStoreWatchPtr 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)
return;
path = event[XS_WATCH_PATH];
token = event[XS_WATCH_TOKEN];
sw = xenStoreFindWatch(priv->xsWatchList, path, token);
if( sw )
sw->cb(conn, path, token, sw->opaque);
VIR_FREE(event);
}
#ifndef PROXY
/* The domain callback for the @introduceDomain watch */
int xenStoreDomainIntroduced(virConnectPtr conn,
const char *path ATTRIBUTE_UNUSED,
const char *token ATTRIBUTE_UNUSED,
void *opaque)
{
int i, j, found, missing = 0, retries = 20;
int new_domain_cnt;
int *new_domids;
int nread;
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
retry:
new_domain_cnt = xenStoreNumOfDomains(conn);
if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
virXenStoreError(NULL, VIR_ERR_NO_MEMORY,
"%s", _("failed to allocate domids"));
return -1;
}
nread = xenStoreListDomains(conn, new_domids, new_domain_cnt);
if (nread != new_domain_cnt) {
// mismatch. retry this read
VIR_FREE(new_domids);
goto retry;
}
missing = 0;
for (i=0 ; i < new_domain_cnt ; i++) {
found = 0;
for (j = 0 ; j < activeDomainList->count ; j++) {
if (activeDomainList->doms[j]->id == new_domids[i]) {
found = 1;
break;
}
}
if (!found) {
virDomainPtr dom;
char *name;
unsigned char uuid[VIR_UUID_BUFLEN];
if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
missing = 1;
continue;
}
if (xenStoreDomainGetUUID(conn, new_domids[i], uuid) < 0) {
missing = 1;
VIR_FREE(name);
continue;
}
dom = virGetDomain(conn, name, uuid);
if (dom) {
dom->id = new_domids[i];
/* This domain was not in the old list. Emit an event */
xenUnifiedDomainEventDispatch(priv, dom,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
/* Add to the list */
xenUnifiedAddDomainInfo(activeDomainList,
new_domids[i], name, uuid);
virUnrefDomain(dom);
}
VIR_FREE(name);
}
}
VIR_FREE(new_domids);
if (missing && retries--) {
DEBUG0("Some domains were missing, trying again");
usleep(100 * 1000);
goto retry;
}
return 0;
}
/* The domain callback for the @destroyDomain watch */
int xenStoreDomainReleased(virConnectPtr conn,
const char *path ATTRIBUTE_UNUSED,
const char *token ATTRIBUTE_UNUSED,
void *opaque)
{
int i, j, found, removed, retries = 20;
int new_domain_cnt;
int *new_domids;
int nread;
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
if(!activeDomainList->count) return 0;
retry:
new_domain_cnt = xenStoreNumOfDomains(conn);
if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
virXenStoreError(NULL, VIR_ERR_NO_MEMORY,
"%s", _("failed to allocate domids"));
return -1;
}
nread = xenStoreListDomains(conn, new_domids, new_domain_cnt);
if (nread != new_domain_cnt) {
// mismatch. retry this read
VIR_FREE(new_domids);
goto retry;
}
removed = 0;
for (j=0 ; j < activeDomainList->count ; j++) {
found = 0;
for (i=0 ; i < new_domain_cnt ; i++) {
if (activeDomainList->doms[j]->id == new_domids[i]) {
found = 1;
break;
}
}
if (!found) {
virDomainPtr dom = virGetDomain(conn,
activeDomainList->doms[j]->name,
activeDomainList->doms[j]->uuid);
if(dom) {
dom->id = -1;
/* This domain was not in the new list. Emit an event */
xenUnifiedDomainEventDispatch(priv, dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
/* Remove from the list */
xenUnifiedRemoveDomainInfo(activeDomainList,
activeDomainList->doms[j]->id,
activeDomainList->doms[j]->name,
activeDomainList->doms[j]->uuid);
virUnrefDomain(dom);
removed = 1;
}
}
}
VIR_FREE(new_domids);
if (!removed && retries--) {
DEBUG0("No domains removed, retrying");
usleep(100 * 1000);
goto retry;
}
return 0;
}
#endif //PROXY

View File

@ -51,5 +51,57 @@ char * xenStoreDomainGetDiskID(virConnectPtr conn,
const char *dev);
char * xenStoreDomainGetName(virConnectPtr conn,
int id);
int xenStoreDomainGetUUID(virConnectPtr conn,
int id,
unsigned char *uuid);
typedef int (*xenStoreWatchCallback)(virConnectPtr conn,
const char *path,
const char *token,
void *opaque);
struct _xenStoreWatch {
char *path;
char *token;
xenStoreWatchCallback cb;
void *opaque;
};
typedef struct _xenStoreWatch xenStoreWatch;
typedef xenStoreWatch *xenStoreWatchPtr;
struct _xenStoreWatchList {
unsigned int count;
xenStoreWatchPtr *watches;
};
typedef struct _xenStoreWatchList xenStoreWatchList;
typedef xenStoreWatchList *xenStoreWatchListPtr;
void xenStoreWatchListFree(xenStoreWatchListPtr head);
int xenStoreAddWatch(virConnectPtr conn,
const char *path,
const char *token,
xenStoreWatchCallback cb,
void *opaque);
int xenStoreRemoveWatch(virConnectPtr conn,
const char *path,
const char *token);
xenStoreWatchPtr xenStoreFindWatch(xenStoreWatchListPtr list,
const char *path,
const char *token);
void xenStoreWatchEvent(int watch, 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__ */