libvirt/src/xen/xen_inotify.c

492 lines
15 KiB
C
Raw Normal View History

/*
* xen_inofify.c: Xen notification of xml file activity in the
* following dirs:
* /etc/xen
* /var/lib/xend/domains
*
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
* Copyright (C) 2010 Red Hat, Inc.
* 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_driver.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 VIR_FROM_THIS VIR_FROM_XEN_INOTIFY
#define virXenInotifyError(code, ...) \
virReportErrorHelper(NULL, VIR_FROM_XEN_INOTIFY, code, __FILE__, \
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
__FUNCTION__, __LINE__, __VA_ARGS__)
struct xenUnifiedDriver xenInotifyDriver = {
xenInotifyOpen, /* open */
xenInotifyClose, /* close */
NULL, /* version */
NULL, /* hostname */
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, /* domainAttachDeviceFlags */
NULL, /* domainDetachDeviceFlags */
NULL, /* domainUpdateDeviceFlags */
NULL, /* domainGetAutostart */
NULL, /* domainSetAutostart */
NULL, /* domainGetSchedulerType */
NULL, /* domainGetSchedulerParameters */
NULL, /* domainSetSchedulerParameters */
};
2008-12-04 21:09:20 +00:00
static int
xenInotifyXenCacheLookup(virConnectPtr conn,
const char *filename,
2008-12-04 21:09:20 +00:00
char **name, unsigned char *uuid) {
xenUnifiedPrivatePtr priv = conn->privateData;
xenXMConfCachePtr entry;
if (!(entry = virHashLookup(priv->configCache, filename))) {
DEBUG("No config found for %s", filename);
2008-12-04 21:09:20 +00:00
return -1;
}
2008-12-04 21:09:20 +00:00
*name = strdup(entry->def->name);
memcpy(uuid, entry->def->uuid, VIR_UUID_BUFLEN);
if (!*name) {
DEBUG0("Error getting dom from def");
virReportOOMError();
2008-12-04 21:09:20 +00:00
return -1;
}
2008-12-04 21:09:20 +00:00
return 0;
}
2008-12-04 21:09:20 +00:00
static int
xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename,
char **name, unsigned char *uuid) {
int i;
virDomainPtr dom;
const char *uuid_str;
2008-12-04 21:09:20 +00:00
unsigned char rawuuid[VIR_UUID_BUFLEN];
xenUnifiedPrivatePtr priv = conn->privateData;
/* xend is managing domains. we will get
* a filename in the manner:
* /var/lib/xend/domains/<uuid>/
*/
uuid_str = filename + strlen(XEND_DOMAINS_DIR) + 1;
2008-12-04 21:09:20 +00:00
if (virUUIDParse(uuid_str, rawuuid) < 0) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
_("parsing uuid %s"), uuid_str);
2008-12-04 21:09:20 +00:00
return -1;
}
/* 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);
2008-12-04 21:09:20 +00:00
/* XXX Should not have to go via a virDomainPtr obj instance */
if(!(dom = xenDaemonLookupByUUID(conn, rawuuid))) {
/* If we are here, the domain has gone away.
search for, and create a domain from the stored
list info */
for (i = 0 ; i < priv->configInfoList->count ; i++) {
if (!memcmp(rawuuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
*name = strdup(priv->configInfoList->doms[i]->name);
2008-12-04 21:09:20 +00:00
if (!*name) {
virReportOOMError();
2008-12-04 21:09:20 +00:00
return -1;
}
memcpy(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN);
DEBUG0("Found dom on list");
2008-12-04 21:09:20 +00:00
return 0;
}
}
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
2008-12-04 21:09:20 +00:00
"%s", _("finding dom on config list"));
return -1;
}
if (!(*name = strdup(dom->name))) {
virReportOOMError();
2008-12-04 21:09:20 +00:00
return -1;
}
2008-12-04 21:09:20 +00:00
memcpy(uuid, dom->uuid, VIR_UUID_BUFLEN);
virDomainFree(dom);
/* succeeded too find domain by uuid */
2008-12-04 21:09:20 +00:00
return 0;
}
2008-12-04 21:09:20 +00:00
static int
xenInotifyDomainLookup(virConnectPtr conn,
const char *filename,
char **name, unsigned char *uuid) {
xenUnifiedPrivatePtr priv = conn->privateData;
if (priv->useXenConfigCache)
return xenInotifyXenCacheLookup(conn, filename, name, uuid);
2008-12-04 21:09:20 +00:00
else
return xenInotifyXendDomainsDirLookup(conn, filename, name, uuid);
}
static virDomainEventPtr
xenInotifyDomainEventFromFile(virConnectPtr conn,
const char *filename,
int type, int detail) {
virDomainEventPtr event;
char *name = NULL;
unsigned char uuid[VIR_UUID_BUFLEN];
if (xenInotifyDomainLookup(conn, filename, &name, uuid) < 0)
return NULL;
event = virDomainEventNew(-1, name, uuid, type, detail);
VIR_FREE(name);
return event;
}
static int
xenInotifyXendDomainsDirRemoveEntry(virConnectPtr conn,
const char *fname) {
xenUnifiedPrivatePtr priv = conn->privateData;
const char *uuidstr = fname + strlen(XEND_DOMAINS_DIR) + 1;
unsigned char uuid[VIR_UUID_BUFLEN];
int i;
if (virUUIDParse(uuidstr, uuid) < 0) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
_("parsing uuid %s"), uuidstr);
return -1;
}
/* match and remove on uuid */
for (i = 0 ; i < priv->configInfoList->count ; i++) {
if (!memcmp(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
VIR_FREE(priv->configInfoList->doms[i]->name);
VIR_FREE(priv->configInfoList->doms[i]);
if (i < (priv->configInfoList->count - 1))
memmove(priv->configInfoList->doms + i,
priv->configInfoList->doms + i + 1,
sizeof(*(priv->configInfoList->doms)) *
(priv->configInfoList->count - (i + 1)));
if (VIR_REALLOC_N(priv->configInfoList->doms,
priv->configInfoList->count - 1) < 0) {
; /* Failure to reduce memory allocation isn't fatal */
}
priv->configInfoList->count--;
return 0;
}
}
return -1;
}
static int
xenInotifyXendDomainsDirAddEntry(virConnectPtr conn,
const char *fname) {
2008-12-04 21:09:20 +00:00
char *name = NULL;
unsigned char uuid[VIR_UUID_BUFLEN];
xenUnifiedPrivatePtr priv = conn->privateData;
2008-12-04 21:09:20 +00:00
if (xenInotifyDomainLookup(conn, fname, &name, uuid) < 0) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
2008-12-04 21:09:20 +00:00
"%s", _("Error looking up domain"));
return -1;
}
if (xenUnifiedAddDomainInfo(priv->configInfoList,
2008-12-04 21:09:20 +00:00
-1, name, uuid) < 0) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
2008-12-04 21:09:20 +00:00
VIR_FREE(name);
return -1;
}
2008-12-04 21:09:20 +00:00
VIR_FREE(name);
return 0;
}
static int
xenInotifyRemoveDomainConfigInfo(virConnectPtr conn,
const char *fname) {
xenUnifiedPrivatePtr priv = conn->privateData;
return priv->useXenConfigCache ?
xenXMConfigCacheRemoveFile(conn, fname) :
xenInotifyXendDomainsDirRemoveEntry(conn, fname);
}
static int
xenInotifyAddDomainConfigInfo(virConnectPtr conn,
const char *fname) {
xenUnifiedPrivatePtr priv = conn->privateData;
return priv->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 = data;
xenUnifiedPrivatePtr priv = NULL;
DEBUG0("got inotify event");
if( conn && conn->privateData ) {
priv = conn->privateData;
} else {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
"%s", _("conn, or private data is NULL"));
return;
}
2009-01-21 18:11:14 +00:00
xenUnifiedLock(priv);
reread:
got = read(fd, buf, sizeof(buf));
if (got == -1) {
if (errno == EINTR)
goto reread;
2009-01-21 18:11:14 +00:00
goto cleanup;
}
tmp = buf;
while (got) {
if (got < sizeof(struct inotify_event))
2009-01-21 18:11:14 +00:00
goto cleanup; /* bad */
e = (struct inotify_event *)tmp;
tmp += sizeof(struct inotify_event);
got -= sizeof(struct inotify_event);
if (got < e->len)
2009-01-21 18:11:14 +00:00
goto cleanup;
tmp += e->len;
got -= e->len;
name = (char *)&(e->name);
snprintf(fname, 1024, "%s/%s",
priv->configDir, name);
if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
2008-12-04 21:09:20 +00:00
virDomainEventPtr event =
xenInotifyDomainEventFromFile(conn, fname,
VIR_DOMAIN_EVENT_UNDEFINED,
VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
if (event)
2008-12-04 21:09:20 +00:00
xenUnifiedDomainEventDispatch(conn->privateData, event);
else
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
2008-12-04 21:09:20 +00:00
"%s", _("looking up dom"));
if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
2009-01-21 18:11:14 +00:00
goto cleanup;
}
} else if (e->mask & ( IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO) ) {
2008-12-04 21:09:20 +00:00
virDomainEventPtr event;
if (xenInotifyAddDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
2009-01-21 18:11:14 +00:00
goto cleanup;
}
2008-12-04 21:09:20 +00:00
event = xenInotifyDomainEventFromFile(conn, fname,
VIR_DOMAIN_EVENT_DEFINED,
VIR_DOMAIN_EVENT_DEFINED_ADDED);
if (event)
xenUnifiedDomainEventDispatch(conn->privateData, event);
else
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
2008-12-04 21:09:20 +00:00
"%s", _("looking up dom"));
}
}
2009-01-21 18:11:14 +00:00
cleanup:
xenUnifiedUnlock(priv);
}
/**
* 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.
*/
virDrvOpenStatus
xenInotifyOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED)
{
DIR *dh;
struct dirent *ent;
char path[PATH_MAX];
xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
if (priv->configDir) {
priv->useXenConfigCache = 1;
} else {
/* /var/lib/xend/domains/<uuid>/config.sxp */
priv->configDir = XEND_DOMAINS_DIR;
priv->useXenConfigCache = 0;
if (VIR_ALLOC(priv->configInfoList) < 0) {
virReportOOMError();
return -1;
}
/* populate initial list */
if (!(dh = opendir(priv->configDir))) {
virReportSystemError(errno,
_("cannot open directory: %s"),
priv->configDir);
return -1;
}
while ((ent = readdir(dh))) {
if (STRPREFIX(ent->d_name, "."))
continue;
/* Build the full file path */
if ((strlen(priv->configDir) + 1 +
strlen(ent->d_name) + 1) > PATH_MAX)
continue;
strcpy(path, priv->configDir);
strcat(path, "/");
strcat(path, ent->d_name);
if (xenInotifyAddDomainConfigInfo(conn, path) < 0 ) {
virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config list"));
closedir(dh);
return -1;
}
}
2008-11-30 18:37:35 +00:00
closedir(dh);
}
if ((priv->inotifyFD = inotify_init()) < 0) {
virReportSystemError(errno,
"%s", _("initializing inotify"));
return -1;
}
DEBUG("Adding a watch on %s", priv->configDir);
if (inotify_add_watch(priv->inotifyFD,
priv->configDir,
IN_CREATE |
IN_CLOSE_WRITE | IN_DELETE |
IN_MOVED_TO | IN_MOVED_FROM) < 0) {
virReportSystemError(errno,
_("adding watch on %s"),
priv->configDir);
return -1;
}
DEBUG0("Building initial config cache");
if (priv->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");
}
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 = conn->privateData;
if (priv->configInfoList)
xenUnifiedDomainInfoListFree(priv->configInfoList);
if (priv->inotifyWatch != -1)
virEventRemoveHandle(priv->inotifyWatch);
close(priv->inotifyFD);
return 0;
}