libvirt/src/xen/xs_internal.c

1389 lines
36 KiB
C
Raw Normal View History

/*
* xs_internal.c: access to Xen Store
*
* Copyright (C) 2006, 2009-2013 Red Hat, Inc.
*
* 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, see
* <http://www.gnu.org/licenses/>.
*
* Daniel Veillard <veillard@redhat.com>
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <xen/dom0_ops.h>
#include <xen/version.h>
#if HAVE_XENSTORE_H
# include <xenstore.h>
#else
# include <xs.h>
#endif
#include "virerror.h"
#include "datatypes.h"
#include "driver.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
2012-12-13 18:01:25 +00:00
#include "viruuid.h"
#include "xen_driver.h"
#include "xs_internal.h"
#include "xen_hypervisor.h"
#define VIR_FROM_THIS VIR_FROM_XEN
static char *xenStoreDomainGetOSType(virDomainPtr domain);
2009-01-21 18:11:14 +00:00
static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
static void xenStoreWatchListFree(xenStoreWatchListPtr list);
struct xenUnifiedDriver xenStoreDriver = {
.xenClose = xenStoreClose,
.xenDomainShutdown = xenStoreDomainShutdown,
.xenDomainReboot = xenStoreDomainReboot,
.xenDomainGetOSType = xenStoreDomainGetOSType,
.xenDomainGetMaxMemory = xenStoreDomainGetMaxMemory,
.xenDomainSetMemory = xenStoreDomainSetMemory,
.xenDomainGetInfo = xenStoreGetDomainInfo,
};
/************************************************************************
* *
* Helper internal APIs *
* *
************************************************************************/
/**
* virConnectDoStoreList:
* @conn: pointer to the hypervisor connection
* @path: the absolute path of the directory in the store to list
* @nb: OUT pointer to the number of items found
*
* Internal API querying the Xenstore for a list
*
* Returns a string which must be freed by the caller or NULL in case of error
*/
static char **
virConnectDoStoreList(virConnectPtr conn, const char *path, unsigned int *nb)
{
xenUnifiedPrivatePtr priv = conn->privateData;
return xs_directory(priv->xshandle, 0, path, nb);
}
/**
* virDomainDoStoreQuery:
* @conn: pointer to the hypervisor connection
* @domid: id of the domain
* @path: the relative path of the data in the store to retrieve
*
* Internal API querying the Xenstore for a string value.
*
* Returns a string which must be freed by the caller or NULL in case of error
*/
static char *
virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
{
char s[256];
unsigned int len = 0;
xenUnifiedPrivatePtr priv = conn->privateData;
if (priv->xshandle == NULL)
return NULL;
snprintf(s, 255, "/local/domain/%d/%s", domid, path);
s[255] = 0;
return xs_read(priv->xshandle, 0, &s[0], &len);
}
/**
* virDomainDoStoreWrite:
* @domain: a domain object
* @path: the relative path of the data in the store to retrieve
*
* Internal API setting up a string value in the Xenstore
* Requires write access to the XenStore
*
* Returns 0 in case of success, -1 in case of failure
*/
static int
virDomainDoStoreWrite(virDomainPtr domain, const char *path, const char *value)
{
char s[256];
xenUnifiedPrivatePtr priv = domain->conn->privateData;
int ret = -1;
if (priv->xshandle == NULL || domain->conn->flags & VIR_CONNECT_RO)
return -1;
snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
s[255] = 0;
if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
ret = 0;
return ret;
}
/**
* virDomainGetVM:
* @domain: a domain object
*
* Internal API extracting a xenstore vm path.
*
* Returns the new string or NULL in case of error
*/
static char *
virDomainGetVM(virDomainPtr domain)
{
char *vm;
char query[200];
unsigned int len;
xenUnifiedPrivatePtr priv = domain->conn->privateData;
if (priv->xshandle == NULL)
return NULL;
snprintf(query, 199, "/local/domain/%d/vm", virDomainGetID(domain));
query[199] = 0;
vm = xs_read(priv->xshandle, 0, &query[0], &len);
return vm;
}
/**
* virDomainGetVMInfo:
* @domain: a domain object
* @vm: the xenstore vm path
* @name: the value's path
*
* Internal API extracting one information the device used
* by the domain from xensttore
*
* Returns the new string or NULL in case of error
*/
static char *
virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
{
char s[256];
char *ret = NULL;
unsigned int len = 0;
xenUnifiedPrivatePtr priv = domain->conn->privateData;
if (priv->xshandle == NULL)
return NULL;
snprintf(s, 255, "%s/%s", vm, name);
s[255] = 0;
ret = xs_read(priv->xshandle, 0, &s[0], &len);
return ret;
}
/************************************************************************
* *
* Canonical internal APIs *
* *
************************************************************************/
/**
* xenStoreOpen:
* @conn: pointer to the connection block
* @name: URL for the target, NULL for local
* @flags: combination of virDrvOpenFlag(s)
*
* Connects to the Xen hypervisor.
*
* Returns 0 or -1 in case of error.
*/
virDrvOpenStatus
xenStoreOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
unsigned int flags)
{
xenUnifiedPrivatePtr priv = conn->privateData;
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
if (flags & VIR_CONNECT_RO)
priv->xshandle = xs_daemon_open_readonly();
else
priv->xshandle = xs_daemon_open();
if (priv->xshandle == NULL) {
/*
2009-01-22 17:49:41 +00:00
* not being able to connect via the socket as an unprivileged
* user is rather normal, this should fallback to the proxy (or
* remote) mechanism.
*/
2009-01-22 17:49:41 +00:00
if (xenHavePrivilege()) {
virReportError(VIR_ERR_NO_XEN,
"%s", _("failed to connect to Xen Store"));
}
return -1;
}
/* Init activeDomainList */
if (VIR_ALLOC(priv->activeDomainList) < 0) {
virReportOOMError();
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) {
virReportOOMError();
return -1;
}
/* This will get called once at start */
if (xenStoreAddWatch(conn, "@releaseDomain",
"releaseDomain", xenStoreDomainReleased, priv) < 0)
{
virReportError(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)
{
virReportError(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)
VIR_DEBUG("Failed to add event handle, disabling events");
return 0;
}
/**
* xenStoreClose:
* @conn: pointer to the connection block
*
* Close the connection to the Xen hypervisor.
*
* Returns 0 in case of success or -1 in case of error.
*/
int
xenStoreClose(virConnectPtr conn)
{
xenUnifiedPrivatePtr priv = conn->privateData;
if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
VIR_DEBUG("Warning, could not remove @introduceDomain watch");
/* not fatal */
}
if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
VIR_DEBUG("Warning, could not remove @releaseDomain watch");
/* not fatal */
}
xenStoreWatchListFree(priv->xsWatchList);
2009-01-15 01:21:36 +00:00
priv->xsWatchList = NULL;
xenUnifiedDomainInfoListFree(priv->activeDomainList);
priv->activeDomainList = NULL;
if (priv->xshandle == NULL)
return -1;
if (priv->xsWatch != -1)
virEventRemoveHandle(priv->xsWatch);
xs_daemon_close(priv->xshandle);
priv->xshandle = NULL;
return 0;
}
/**
* xenStoreGetDomainInfo:
* @domain: pointer to the domain block
* @info: the place where information should be stored
*
* Do a hypervisor call to get the related set of domain information.
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
{
char *tmp, **tmp2;
unsigned int nb_vcpus;
char request[200];
xenUnifiedPrivatePtr priv = domain->conn->privateData;
if (priv->xshandle == NULL || domain->id == -1)
return -1;
tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
if (tmp != NULL) {
if (tmp[0] == '1')
info->state = VIR_DOMAIN_RUNNING;
VIR_FREE(tmp);
} else {
2008-07-08 17:49:26 +00:00
info->state = VIR_DOMAIN_NOSTATE;
}
tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
if (tmp != NULL) {
info->memory = atol(tmp);
info->maxMem = atol(tmp);
VIR_FREE(tmp);
} else {
info->memory = 0;
info->maxMem = 0;
}
#if 0
/* doesn't seems to work */
tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
if (tmp != NULL) {
info->cpuTime = atol(tmp);
VIR_FREE(tmp);
} else {
info->cpuTime = 0;
}
#endif
snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
request[199] = 0;
tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
if (tmp2 != NULL) {
info->nrVirtCpu = nb_vcpus;
VIR_FREE(tmp2);
}
return 0;
}
/**
* xenStoreDomainGetState:
* @domain: pointer to the domain block
* @state: returned domain's state
* @reason: returned state reason
* @flags: additional flags, 0 for now
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenStoreDomainGetState(virDomainPtr domain,
int *state,
int *reason,
unsigned int flags)
{
char *running;
virCheckFlags(0, -1);
if (domain->id == -1)
return -1;
running = virDomainDoStoreQuery(domain->conn, domain->id, "running");
if (running && *running == '1')
*state = VIR_DOMAIN_RUNNING;
else
*state = VIR_DOMAIN_NOSTATE;
if (reason)
*reason = 0;
VIR_FREE(running);
return 0;
}
/**
* xenStoreDomainSetMemory:
* @domain: pointer to the domain block
* @memory: the max memory size in kilobytes.
*
* Change the maximum amount of memory allowed in the xen store
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
int ret;
char value[20];
if (memory < 1024 * MIN_XEN_GUEST_SIZE) {
virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
return -1;
}
if (domain->id == -1)
return -1;
2007-03-08 14:17:32 +00:00
if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
return -1;
snprintf(value, 19, "%lu", memory);
value[19] = 0;
ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
if (ret < 0)
return -1;
return 0;
}
/**
* xenStoreDomainGetMaxMemory:
* @domain: pointer to the domain block
*
* Ask the xenstore for the maximum memory allowed for a domain
*
* Returns the memory size in kilobytes or 0 in case of error.
*/
xml: use long long internally, to centralize overflow checks On 64-bit platforms, unsigned long and unsigned long long are identical, so we don't have to worry about overflow checks. On 32-bit platforms, anywhere we narrow unsigned long long back to unsigned long, we have to worry about overflow; it's easier to do this in one place by having most of the code use the same or wider types, and only doing the narrowing at the last minute. Therefore, the memory set commands remain unsigned long, and the memory get command now centralizes the overflow check into libvirt.c, so that drivers don't have to repeat the work. This also fixes a bug where xen returned the wrong value on failure (most APIs return -1 on failure, but getMaxMemory must return 0 on failure). * src/driver.h (virDrvDomainGetMaxMemory): Use long long. * src/libvirt.c (virDomainGetMaxMemory): Raise overflow. * src/test/test_driver.c (testGetMaxMemory): Fix driver. * src/rpc/gendispatch.pl (name_to_ProcName): Likewise. * src/xen/xen_hypervisor.c (xenHypervisorGetMaxMemory): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainGetMaxMemory): Likewise. * src/xen/xend_internal.c (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xend_internal.h (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xm_internal.c (xenXMDomainGetMaxMemory): Likewise. * src/xen/xm_internal.h (xenXMDomainGetMaxMemory): Likewise. * src/xen/xs_internal.c (xenStoreDomainGetMaxMemory): Likewise. * src/xen/xs_internal.h (xenStoreDomainGetMaxMemory): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainGetMaxMemory): Likewise. * src/esx/esx_driver.c (esxDomainGetMaxMemory): Likewise. * src/libxl/libxl_driver.c (libxlDomainGetMaxMemory): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetMaxMemory): Likewise. * src/lxc/lxc_driver.c (lxcDomainGetMaxMemory): Likewise. * src/uml/uml_driver.c (umlDomainGetMaxMemory): Likewise.
2012-03-03 00:47:16 +00:00
unsigned long long
xenStoreDomainGetMaxMemory(virDomainPtr domain)
{
char *tmp;
xml: use long long internally, to centralize overflow checks On 64-bit platforms, unsigned long and unsigned long long are identical, so we don't have to worry about overflow checks. On 32-bit platforms, anywhere we narrow unsigned long long back to unsigned long, we have to worry about overflow; it's easier to do this in one place by having most of the code use the same or wider types, and only doing the narrowing at the last minute. Therefore, the memory set commands remain unsigned long, and the memory get command now centralizes the overflow check into libvirt.c, so that drivers don't have to repeat the work. This also fixes a bug where xen returned the wrong value on failure (most APIs return -1 on failure, but getMaxMemory must return 0 on failure). * src/driver.h (virDrvDomainGetMaxMemory): Use long long. * src/libvirt.c (virDomainGetMaxMemory): Raise overflow. * src/test/test_driver.c (testGetMaxMemory): Fix driver. * src/rpc/gendispatch.pl (name_to_ProcName): Likewise. * src/xen/xen_hypervisor.c (xenHypervisorGetMaxMemory): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainGetMaxMemory): Likewise. * src/xen/xend_internal.c (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xend_internal.h (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xm_internal.c (xenXMDomainGetMaxMemory): Likewise. * src/xen/xm_internal.h (xenXMDomainGetMaxMemory): Likewise. * src/xen/xs_internal.c (xenStoreDomainGetMaxMemory): Likewise. * src/xen/xs_internal.h (xenStoreDomainGetMaxMemory): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainGetMaxMemory): Likewise. * src/esx/esx_driver.c (esxDomainGetMaxMemory): Likewise. * src/libxl/libxl_driver.c (libxlDomainGetMaxMemory): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetMaxMemory): Likewise. * src/lxc/lxc_driver.c (lxcDomainGetMaxMemory): Likewise. * src/uml/uml_driver.c (umlDomainGetMaxMemory): Likewise.
2012-03-03 00:47:16 +00:00
unsigned long long ret = 0;
xenUnifiedPrivatePtr priv = domain->conn->privateData;
if (domain->id == -1)
xml: use long long internally, to centralize overflow checks On 64-bit platforms, unsigned long and unsigned long long are identical, so we don't have to worry about overflow checks. On 32-bit platforms, anywhere we narrow unsigned long long back to unsigned long, we have to worry about overflow; it's easier to do this in one place by having most of the code use the same or wider types, and only doing the narrowing at the last minute. Therefore, the memory set commands remain unsigned long, and the memory get command now centralizes the overflow check into libvirt.c, so that drivers don't have to repeat the work. This also fixes a bug where xen returned the wrong value on failure (most APIs return -1 on failure, but getMaxMemory must return 0 on failure). * src/driver.h (virDrvDomainGetMaxMemory): Use long long. * src/libvirt.c (virDomainGetMaxMemory): Raise overflow. * src/test/test_driver.c (testGetMaxMemory): Fix driver. * src/rpc/gendispatch.pl (name_to_ProcName): Likewise. * src/xen/xen_hypervisor.c (xenHypervisorGetMaxMemory): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainGetMaxMemory): Likewise. * src/xen/xend_internal.c (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xend_internal.h (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xm_internal.c (xenXMDomainGetMaxMemory): Likewise. * src/xen/xm_internal.h (xenXMDomainGetMaxMemory): Likewise. * src/xen/xs_internal.c (xenStoreDomainGetMaxMemory): Likewise. * src/xen/xs_internal.h (xenStoreDomainGetMaxMemory): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainGetMaxMemory): Likewise. * src/esx/esx_driver.c (esxDomainGetMaxMemory): Likewise. * src/libxl/libxl_driver.c (libxlDomainGetMaxMemory): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetMaxMemory): Likewise. * src/lxc/lxc_driver.c (lxcDomainGetMaxMemory): Likewise. * src/uml/uml_driver.c (umlDomainGetMaxMemory): Likewise.
2012-03-03 00:47:16 +00:00
return 0;
2009-01-21 18:11:14 +00:00
xenUnifiedLock(priv);
tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
if (tmp != NULL) {
xml: use long long internally, to centralize overflow checks On 64-bit platforms, unsigned long and unsigned long long are identical, so we don't have to worry about overflow checks. On 32-bit platforms, anywhere we narrow unsigned long long back to unsigned long, we have to worry about overflow; it's easier to do this in one place by having most of the code use the same or wider types, and only doing the narrowing at the last minute. Therefore, the memory set commands remain unsigned long, and the memory get command now centralizes the overflow check into libvirt.c, so that drivers don't have to repeat the work. This also fixes a bug where xen returned the wrong value on failure (most APIs return -1 on failure, but getMaxMemory must return 0 on failure). * src/driver.h (virDrvDomainGetMaxMemory): Use long long. * src/libvirt.c (virDomainGetMaxMemory): Raise overflow. * src/test/test_driver.c (testGetMaxMemory): Fix driver. * src/rpc/gendispatch.pl (name_to_ProcName): Likewise. * src/xen/xen_hypervisor.c (xenHypervisorGetMaxMemory): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainGetMaxMemory): Likewise. * src/xen/xend_internal.c (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xend_internal.h (xenDaemonDomainGetMaxMemory): Likewise. * src/xen/xm_internal.c (xenXMDomainGetMaxMemory): Likewise. * src/xen/xm_internal.h (xenXMDomainGetMaxMemory): Likewise. * src/xen/xs_internal.c (xenStoreDomainGetMaxMemory): Likewise. * src/xen/xs_internal.h (xenStoreDomainGetMaxMemory): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainGetMaxMemory): Likewise. * src/esx/esx_driver.c (esxDomainGetMaxMemory): Likewise. * src/libxl/libxl_driver.c (libxlDomainGetMaxMemory): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetMaxMemory): Likewise. * src/lxc/lxc_driver.c (lxcDomainGetMaxMemory): Likewise. * src/uml/uml_driver.c (umlDomainGetMaxMemory): Likewise.
2012-03-03 00:47:16 +00:00
ret = atol(tmp);
2009-01-21 18:11:14 +00:00
VIR_FREE(tmp);
}
2009-01-21 18:11:14 +00:00
xenUnifiedUnlock(priv);
return ret;
}
/**
* xenStoreNumOfDomains:
* @conn: pointer to the hypervisor connection
*
* Provides the number of active domains.
*
* Returns the number of domain found or -1 in case of error
*/
int
xenStoreNumOfDomains(virConnectPtr conn)
{
unsigned int num;
char **idlist = NULL, *endptr;
int i, ret = -1, realnum = 0;
long id;
xenUnifiedPrivatePtr priv = conn->privateData;
if (priv->xshandle == NULL) {
virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
return -1;
}
idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
if (idlist) {
for (i = 0; i < num; i++) {
id = strtol(idlist[i], &endptr, 10);
if ((endptr == idlist[i]) || (*endptr != 0))
goto out;
/* Sometimes xenstore has stale domain IDs, so filter
against the hypervisor's info */
if (xenHypervisorHasDomain(conn, (int)id))
realnum++;
}
out:
VIR_FREE(idlist);
ret = realnum;
}
return ret;
}
/**
* xenStoreDoListDomains:
* @conn: pointer to the hypervisor connection
* @ids: array to collect the list of IDs of active domains
* @maxids: size of @ids
*
* Internal API: collect the list of active domains, and store
* their ID in @maxids. The driver lock must be held.
*
* Returns the number of domain found or -1 in case of error
*/
static int
xenStoreDoListDomains(virConnectPtr conn,
xenUnifiedPrivatePtr priv,
int *ids,
int maxids)
{
char **idlist = NULL, *endptr;
unsigned int num, i;
int ret = -1;
long id;
2009-01-21 18:11:14 +00:00
if (priv->xshandle == NULL)
goto out;
idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
if (idlist == NULL)
goto out;
for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
id = strtol(idlist[i], &endptr, 10);
if ((endptr == idlist[i]) || (*endptr != 0))
goto out;
/* Sometimes xenstore has stale domain IDs, so filter
against the hypervisor's info */
if (xenHypervisorHasDomain(conn, (int)id))
ids[ret++] = (int) id;
}
out:
VIR_FREE(idlist);
return ret;
}
/**
* xenStoreListDomains:
* @conn: pointer to the hypervisor connection
* @ids: array to collect the list of IDs of active domains
* @maxids: size of @ids
*
* Collect the list of active domains, and store their ID in @maxids
*
* Returns the number of domain found or -1 in case of error
*/
int
xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
{
xenUnifiedPrivatePtr priv = conn->privateData;
int ret;
xenUnifiedLock(priv);
ret = xenStoreDoListDomains(conn, priv, ids, maxids);
2009-01-21 18:11:14 +00:00
xenUnifiedUnlock(priv);
return ret;
}
/**
* xenStoreLookupByName:
* @conn: A xend instance
* @name: The name of the domain
*
* Try to lookup a domain on the Xen Store based on its name.
*
* Returns a new domain object or NULL in case of failure
*/
virDomainPtr
xenStoreLookupByName(virConnectPtr conn, const char *name)
{
virDomainPtr ret = NULL;
unsigned int num, i, len;
long id = -1;
char **idlist = NULL, *endptr;
char prop[200], *tmp;
int found = 0;
struct xend_domain *xenddomain = NULL;
xenUnifiedPrivatePtr priv = conn->privateData;
if (priv->xshandle == NULL)
return NULL;
idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
if (idlist == NULL)
goto done;
for (i = 0; i < num; i++) {
id = strtol(idlist[i], &endptr, 10);
if ((endptr == idlist[i]) || (*endptr != 0)) {
goto done;
}
#if 0
if (virConnectCheckStoreID(conn, (int) id) < 0)
continue;
#endif
snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
prop[199] = 0;
tmp = xs_read(priv->xshandle, 0, prop, &len);
if (tmp != NULL) {
found = STREQ(name, tmp);
VIR_FREE(tmp);
if (found)
break;
}
}
if (!found)
goto done;
ret = virGetDomain(conn, name, NULL);
if (ret == NULL)
goto done;
ret->id = id;
done:
VIR_FREE(xenddomain);
VIR_FREE(idlist);
return ret;
}
/**
* xenStoreDomainShutdown:
* @domain: pointer to the Domain block
*
* Shutdown the domain, the OS is requested to properly shutdown
* and the domain may ignore it. It will return immediately
* after queuing the request.
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenStoreDomainShutdown(virDomainPtr domain)
{
2009-01-21 18:11:14 +00:00
int ret;
xenUnifiedPrivatePtr priv = domain->conn->privateData;
2009-01-21 18:11:14 +00:00
2007-02-22 16:49:12 +00:00
if (domain->id == -1 || domain->id == 0)
return -1;
/*
* this is very hackish, the domU kernel probes for a special
* node in the xenstore and launch the shutdown command if found.
*/
2009-01-21 18:11:14 +00:00
xenUnifiedLock(priv);
ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
xenUnifiedUnlock(priv);
return ret;
}
/**
* xenStoreDomainReboot:
* @domain: pointer to the Domain block
* @flags: extra flags for the reboot operation, not used yet
*
* Reboot the domain, the OS is requested to properly shutdown
* and reboot but the domain may ignore it. It will return immediately
* after queuing the request.
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenStoreDomainReboot(virDomainPtr domain, unsigned int flags)
{
2009-01-21 18:11:14 +00:00
int ret;
xenUnifiedPrivatePtr priv = domain->conn->privateData;
2009-01-21 18:11:14 +00:00
virCheckFlags(0, -1);
2007-02-22 16:49:12 +00:00
if (domain->id == -1 || domain->id == 0)
return -1;
/*
* this is very hackish, the domU kernel probes for a special
* node in the xenstore and launch the shutdown command if found.
*/
2009-01-21 18:11:14 +00:00
xenUnifiedLock(priv);
ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
xenUnifiedUnlock(priv);
return ret;
}
/*
* xenStoreDomainGetOSType:
* @domain: a domain object
*
* Get the type of domain operation system.
*
* Returns the new string or NULL in case of error, the string must be
* freed by the caller.
*/
static char *
xenStoreDomainGetOSType(virDomainPtr domain)
{
char *vm, *str = NULL;
vm = virDomainGetVM(domain);
if (vm) {
2009-01-21 18:11:14 +00:00
xenUnifiedPrivatePtr priv = domain->conn->privateData;
xenUnifiedLock(priv);
str = virDomainGetVMInfo(domain, vm, "image/ostype");
2009-01-21 18:11:14 +00:00
xenUnifiedUnlock(priv);
VIR_FREE(vm);
}
return str;
}
/**
* xenStoreDomainGetVNCPort:
* @conn: the hypervisor connection
* @domid: id of the domain
*
* Return the port number on which the domain is listening for VNC
* connections.
*
2009-01-21 18:11:14 +00:00
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*
* Returns the port number, -1 in case of error
*/
int
xenStoreDomainGetVNCPort(virConnectPtr conn, int domid)
{
char *tmp;
int ret = -1;
tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
if (tmp != NULL) {
char *end;
ret = strtol(tmp, &end, 10);
if (ret == 0 && end == tmp)
ret = -1;
VIR_FREE(tmp);
}
return ret;
}
/**
* xenStoreDomainGetConsolePath:
* @conn: the hypervisor connection
* @domid: id of the domain
*
* Return the path to the pseudo TTY on which the guest domain's
* serial console is attached.
*
* Returns the path to the serial console. It is the callers
* responsibilty to free() the return string. Returns NULL
* on error
2009-01-21 18:11:14 +00:00
*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*/
char *
xenStoreDomainGetConsolePath(virConnectPtr conn, int domid)
{
return virDomainDoStoreQuery(conn, domid, "console/tty");
}
/**
* xenStoreDomainGetSerailConsolePath:
* @conn: the hypervisor connection
* @domid: id of the domain
*
* Return the path to the pseudo TTY on which the guest domain's
* serial console is attached.
*
* Returns the path to the serial console. It is the callers
* responsibilty to free() the return string. Returns NULL
* on error
*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*/
char *
xenStoreDomainGetSerialConsolePath(virConnectPtr conn, int domid)
{
return virDomainDoStoreQuery(conn, domid, "serial/0/tty");
}
/*
* xenStoreDomainGetNetworkID:
* @conn: pointer to the connection.
* @id: the domain id
* @mac: the mac address
*
* Get the reference (i.e. the string number) for the device on that domain
* which uses the given mac address
*
2009-01-21 18:11:14 +00:00
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*
* Returns the new string or NULL in case of error, the string must be
* freed by the caller.
*/
char *
xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac)
{
char dir[80], path[128], **list = NULL, *val = NULL;
unsigned int len, i, num;
char *ret = NULL;
xenUnifiedPrivatePtr priv = conn->privateData;
if (id < 0 || priv->xshandle == NULL || mac == NULL)
return NULL;
snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
list = xs_directory(priv->xshandle, 0, dir, &num);
if (list == NULL)
return NULL;
for (i = 0; i < num; i++) {
snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
break;
bool match = (virMacAddrCompare(val, mac) == 0);
VIR_FREE(val);
if (match) {
ret = strdup(list[i]);
if (ret == NULL)
virReportOOMError();
break;
}
}
VIR_FREE(list);
return ret;
}
/*
* xenStoreDomainGetDiskID:
* @conn: pointer to the connection.
* @id: the domain id
* @dev: the virtual block device name
*
* Get the reference (i.e. the string number) for the device on that domain
* which uses the given virtual block device name
*
2009-01-21 18:11:14 +00:00
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*
* Returns the new string or NULL in case of error, the string must be
* freed by the caller.
*/
char *
xenStoreDomainGetDiskID(virConnectPtr conn, int id, const char *dev)
{
char dir[80], path[128], **list = NULL, *val = NULL;
unsigned int devlen, len, i, num;
char *ret = NULL;
xenUnifiedPrivatePtr priv = conn->privateData;
if (id < 0 || priv->xshandle == NULL || dev == NULL)
return NULL;
devlen = strlen(dev);
if (devlen <= 0)
return NULL;
snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
list = xs_directory(priv->xshandle, 0, dir, &num);
if (list != NULL) {
for (i = 0; i < num; i++) {
snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
val = xs_read(priv->xshandle, 0, path, &len);
if (val == NULL)
break;
if ((devlen != len) || memcmp(val, dev, len)) {
VIR_FREE(val);
} else {
ret = strdup(list[i]);
if (ret == NULL)
virReportOOMError();
VIR_FREE(val);
VIR_FREE(list);
return ret;
}
}
VIR_FREE(list);
}
snprintf(dir, sizeof(dir), "/local/domain/0/backend/tap/%d", id);
list = xs_directory(priv->xshandle, 0, dir, &num);
if (list != NULL) {
for (i = 0; i < num; i++) {
snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
val = xs_read(priv->xshandle, 0, path, &len);
if (val == NULL)
break;
if ((devlen != len) || memcmp(val, dev, len)) {
VIR_FREE(val);
} else {
ret = strdup(list[i]);
if (ret == NULL)
virReportOOMError();
VIR_FREE(val);
VIR_FREE(list);
return ret;
}
}
VIR_FREE(list);
}
return NULL;
}
/*
* xenStoreDomainGetPCIID:
* @conn: pointer to the connection.
* @id: the domain id
* @bdf: the PCI BDF
*
* Get the reference (i.e. the string number) for the device on that domain
* which uses the given PCI address
*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*
* Returns the new string or NULL in case of error, the string must be
* freed by the caller.
*/
char *
xenStoreDomainGetPCIID(virConnectPtr conn, int id, const char *bdf)
{
char dir[80], path[128], **list = NULL, *val = NULL;
unsigned int len, i, num;
char *ret = NULL;
xenUnifiedPrivatePtr priv = conn->privateData;
if (id < 0 || priv->xshandle == NULL || bdf == NULL)
return NULL;
snprintf(dir, sizeof(dir), "/local/domain/0/backend/pci/%d", id);
list = xs_directory(priv->xshandle, 0, dir, &num);
if (list == NULL)
return NULL;
for (i = 0; i < num; i++) {
snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev-0");
if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
break;
bool match = STREQ(val, bdf);
VIR_FREE(val);
if (match) {
ret = strdup(list[i]);
break;
}
}
VIR_FREE(list);
return ret;
}
2009-01-21 18:11:14 +00:00
/*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*/
char *
xenStoreDomainGetName(virConnectPtr conn, int id)
{
char prop[200];
xenUnifiedPrivatePtr priv = conn->privateData;
unsigned int len;
if (priv->xshandle == NULL)
return NULL;
snprintf(prop, 199, "/local/domain/%d/name", id);
prop[199] = 0;
return xs_read(priv->xshandle, 0, prop, &len);
}
2009-01-21 18:11:14 +00:00
/*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*/
int
xenStoreDomainGetUUID(virConnectPtr conn, int id, unsigned char *uuid)
{
char prop[200];
xenUnifiedPrivatePtr priv = conn->privateData;
unsigned int len;
char *uuidstr;
int ret = 0;
if (priv->xshandle == NULL)
return -1;
snprintf(prop, 199, "/local/domain/%d/vm", id);
prop[199] = 0;
/* This will return something like
xen-xs: fix uuid of renamed domain When the XenStore tdb lives persistently and is not cleared between host reboots, Xend (version 3.4 and 4.1) re-creates the domain information located in XenStore below /vm/$UUID. (According to the xen-3.2-commit hg265950e3df69 to fix a problem when locally migrating a domain to the host itself.) When doing so a version number is added to the UUID separated by one dash, which confuses xenStoreDomainIntroduced(): It iterates over all domains and tries to lookup all inactive domains using xenStoreDomainGetUUID(), which fails if the running domain is renamed: virUUIDParse() fails to parse the versioned UUID and the domain is flagged as missing. When this happens the function delays .2s and re-tries 20 times again, multiplied by the number of renamed VMs. 14:48:38.878: 4285: debug : xenStoreDomainIntroduced:1354 : Some domains were missing, trying again This adds a significant delay: # time virsh list >/dev/null real 0m6.529s # xenstore-list /vm 00000000-0000-0000-0000-000000000000 00000000-0000-0000-0000-000000000000-1 00000000-0000-0000-0000-000000000000-2 00000000-0000-0000-0000-000000000000-3 00000000-0000-0000-0000-000000000000-4 00000000-0000-0000-0000-000000000000-5 7c06121e-90c3-93d4-0126-50481d485cca 00000000-0000-0000-0000-000000000000-6 00000000-0000-0000-0000-000000000000-7 144ad19d-dfb4-2f80-8045-09196bb8784f 00000000-0000-0000-0000-000000000000-8 144ad19d-dfb4-2f80-8045-09196bb8784f-1 00000000-0000-0000-0000-000000000000-9 00000000-0000-0000-0000-000000000000-10 00000000-0000-0000-0000-000000000000-11 00000000-0000-0000-0000-000000000000-12 00000000-0000-0000-0000-000000000000-13 00000000-0000-0000-0000-000000000000-14 144ad19d-dfb4-2f80-8045-09196bb8784f-2 00000000-0000-0000-0000-000000000000-15 144ad19d-dfb4-2f80-8045-09196bb8784f-3 00000000-0000-0000-0000-000000000000-16 The patch adds truncation of the UUID as read from the XenStore path before passing it to virUUIDParse(). The same issue is reported at <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666135> Signed-off-by: Philipp Hahn <hahn@univention.de>
2012-08-24 12:58:52 +00:00
* /vm/00000000-0000-0000-0000-000000000000[-*] */
uuidstr = xs_read(priv->xshandle, 0, prop, &len);
xen-xs: fix uuid of renamed domain When the XenStore tdb lives persistently and is not cleared between host reboots, Xend (version 3.4 and 4.1) re-creates the domain information located in XenStore below /vm/$UUID. (According to the xen-3.2-commit hg265950e3df69 to fix a problem when locally migrating a domain to the host itself.) When doing so a version number is added to the UUID separated by one dash, which confuses xenStoreDomainIntroduced(): It iterates over all domains and tries to lookup all inactive domains using xenStoreDomainGetUUID(), which fails if the running domain is renamed: virUUIDParse() fails to parse the versioned UUID and the domain is flagged as missing. When this happens the function delays .2s and re-tries 20 times again, multiplied by the number of renamed VMs. 14:48:38.878: 4285: debug : xenStoreDomainIntroduced:1354 : Some domains were missing, trying again This adds a significant delay: # time virsh list >/dev/null real 0m6.529s # xenstore-list /vm 00000000-0000-0000-0000-000000000000 00000000-0000-0000-0000-000000000000-1 00000000-0000-0000-0000-000000000000-2 00000000-0000-0000-0000-000000000000-3 00000000-0000-0000-0000-000000000000-4 00000000-0000-0000-0000-000000000000-5 7c06121e-90c3-93d4-0126-50481d485cca 00000000-0000-0000-0000-000000000000-6 00000000-0000-0000-0000-000000000000-7 144ad19d-dfb4-2f80-8045-09196bb8784f 00000000-0000-0000-0000-000000000000-8 144ad19d-dfb4-2f80-8045-09196bb8784f-1 00000000-0000-0000-0000-000000000000-9 00000000-0000-0000-0000-000000000000-10 00000000-0000-0000-0000-000000000000-11 00000000-0000-0000-0000-000000000000-12 00000000-0000-0000-0000-000000000000-13 00000000-0000-0000-0000-000000000000-14 144ad19d-dfb4-2f80-8045-09196bb8784f-2 00000000-0000-0000-0000-000000000000-15 144ad19d-dfb4-2f80-8045-09196bb8784f-3 00000000-0000-0000-0000-000000000000-16 The patch adds truncation of the UUID as read from the XenStore path before passing it to virUUIDParse(). The same issue is reported at <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666135> Signed-off-by: Philipp Hahn <hahn@univention.de>
2012-08-24 12:58:52 +00:00
/* Strip optional version suffix when VM was renamed */
if (len > 40) /* strlen('/vm/') + VIR_UUID_STRING_BUFLEN - sizeof('\0') */
uuidstr[40] = '\0';
/* remove "/vm/" */
ret = virUUIDParse(uuidstr + 4, uuid);
VIR_FREE(uuidstr);
return ret;
}
2009-01-21 18:11:14 +00:00
static 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);
}
2009-01-21 18:11:14 +00:00
/*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*/
int
xenStoreAddWatch(virConnectPtr conn,
const char *path,
const char *token,
xenStoreWatchCallback cb,
void *opaque)
{
xenStoreWatchPtr watch = NULL;
int n;
xenStoreWatchListPtr list;
xenUnifiedPrivatePtr priv = 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)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("watch already tracked"));
return -1;
}
}
if (VIR_ALLOC(watch) < 0)
goto no_memory;
watch->path = strdup(path);
watch->token = strdup(token);
watch->cb = cb;
watch->opaque = opaque;
if (watch->path == NULL || watch->token == NULL) {
goto no_memory;
}
/* Make space on list */
n = list->count;
if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
goto no_memory;
}
list->watches[n] = watch;
list->count++;
return xs_watch(priv->xshandle, watch->path, watch->token);
no_memory:
if (watch) {
VIR_FREE(watch->path);
VIR_FREE(watch->token);
VIR_FREE(watch);
}
virReportOOMError();
return -1;
}
2009-01-21 18:11:14 +00:00
/*
* The caller must hold the lock on the privateData
* associated with the 'conn' parameter.
*/
int
xenStoreRemoveWatch(virConnectPtr conn, const char *path, const char *token)
{
int i;
xenStoreWatchListPtr list;
xenUnifiedPrivatePtr priv = 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]->token))
{
VIR_DEBUG("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--;
return 0;
}
}
return -1;
}
2009-01-21 18:11:14 +00:00
static 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;
}
2009-01-21 18:11:14 +00:00
static void
xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
int fd ATTRIBUTE_UNUSED,
int events, void *data)
{
char **event;
char *path;
char *token;
unsigned int stringCount;
xenStoreWatchPtr sw;
virConnectPtr conn = data;
xenUnifiedPrivatePtr priv = conn->privateData;
if (!priv) return;
2009-01-21 18:11:14 +00:00
/* only set a watch on read and write events */
if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;
2009-01-21 18:11:14 +00:00
xenUnifiedLock(priv);
if (!priv->xshandle)
2009-01-21 18:11:14 +00:00
goto cleanup;
event = xs_read_watch(priv->xshandle, &stringCount);
if (!event)
2009-01-21 18:11:14 +00:00
goto cleanup;
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);
2009-01-21 18:11:14 +00:00
cleanup:
xenUnifiedUnlock(priv);
}
2009-01-21 18:11:14 +00:00
/*
* The domain callback for the @introduceDomain watch
*
* The lock on 'priv' is held when calling this
*/
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 = opaque;
retry:
new_domain_cnt = xenStoreNumOfDomains(conn);
if (new_domain_cnt < 0)
return -1;
if (VIR_ALLOC_N(new_domids,new_domain_cnt) < 0) {
virReportOOMError();
return -1;
}
nread = xenStoreDoListDomains(conn, priv, 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 < priv->activeDomainList->count ; j++) {
if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
found = 1;
break;
}
}
if (!found) {
2008-12-04 21:09:20 +00:00
virDomainEventPtr event;
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;
}
2008-12-04 21:09:20 +00:00
event = virDomainEventNew(new_domids[i], name, uuid,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
if (event)
xenUnifiedDomainEventDispatch(priv, event);
2008-12-04 21:09:20 +00:00
/* Add to the list */
xenUnifiedAddDomainInfo(priv->activeDomainList,
2008-12-04 21:09:20 +00:00
new_domids[i], name, uuid);
VIR_FREE(name);
}
}
VIR_FREE(new_domids);
if (missing && retries--) {
VIR_DEBUG("Some domains were missing, trying again");
usleep(100 * 1000);
goto retry;
}
return 0;
}
2009-01-21 18:11:14 +00:00
/*
* The domain callback for the @destroyDomain watch
*
* The lock on 'priv' is held when calling this
*/
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 = opaque;
if (!priv->activeDomainList->count) return 0;
retry:
new_domain_cnt = xenStoreNumOfDomains(conn);
if (new_domain_cnt < 0)
return -1;
if (VIR_ALLOC_N(new_domids,new_domain_cnt) < 0) {
virReportOOMError();
return -1;
}
nread = xenStoreDoListDomains(conn, priv, 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 < priv->activeDomainList->count ; j++) {
found = 0;
for (i=0 ; i < new_domain_cnt ; i++) {
if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
found = 1;
break;
}
}
if (!found) {
2008-12-04 21:09:20 +00:00
virDomainEventPtr event =
virDomainEventNew(-1,
priv->activeDomainList->doms[j]->name,
priv->activeDomainList->doms[j]->uuid,
2008-12-04 21:09:20 +00:00
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
if (event)
xenUnifiedDomainEventDispatch(priv, event);
/* Remove from the list */
xenUnifiedRemoveDomainInfo(priv->activeDomainList,
priv->activeDomainList->doms[j]->id,
priv->activeDomainList->doms[j]->name,
priv->activeDomainList->doms[j]->uuid);
2008-12-04 21:09:20 +00:00
removed = 1;
}
}
VIR_FREE(new_domids);
if (!removed && retries--) {
VIR_DEBUG("No domains removed, retrying");
usleep(100 * 1000);
goto retry;
}
return 0;
}