mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-20 10:22:18 +00:00
Support domain lifecycle events for Xen (Ben Guthro & Daniel Berrange)
This commit is contained in:
parent
b2dbfefcf3
commit
1eeceaa649
21
ChangeLog
21
ChangeLog
@ -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,
|
||||
|
16
configure.in
16
configure.in
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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__);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
458
src/xen_inotify.c
Normal 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
31
src/xen_inotify.h
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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__ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user