libvirt/src/uml/uml_driver.c

3053 lines
84 KiB
C
Raw Normal View History

2008-11-19 16:58:23 +00:00
/*
* uml_driver.c: core driver methods for managing UML guests
*
* Copyright (C) 2006-2015 Red Hat, Inc.
2008-11-19 16:58:23 +00:00
* Copyright (C) 2006-2008 Daniel P. Berrange
*
* 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/>.
2008-11-19 16:58:23 +00:00
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
#include <pwd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
#include <sys/un.h>
2008-11-19 16:58:23 +00:00
#include "uml_driver.h"
#include "uml_conf.h"
#include "virbuffer.h"
2008-11-19 16:58:23 +00:00
#include "nodeinfo.h"
#include "virstats.h"
2008-11-19 16:58:23 +00:00
#include "capabilities.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
2012-12-13 18:01:25 +00:00
#include "viruuid.h"
2008-11-19 16:58:23 +00:00
#include "domain_conf.h"
#include "domain_audit.h"
2008-11-19 16:58:23 +00:00
#include "datatypes.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
#include "domain_nwfilter.h"
#include "nwfilter_conf.h"
#include "virfile.h"
#include "fdstream.h"
maint: use gnulib configmake rather than open-coding things * bootstrap.conf (gnulib_modules): Add configmake. * daemon/Makefile.am (libvirtd_CFLAGS): Drop defines provided by gnulib. * src/Makefile.am (INCLUDES): Likewise. * tests/Makefile.am (INCLUDES): Likewise. * tools/Makefile.am (virsh_CFLAGS): Likewise. * daemon/libvirtd.c (qemudInitPaths, usage, main): Update clients. * src/cpu/cpu_map.c (CPUMAPFILE): Likewise. * src/driver.c (DEFAULT_DRIVER_DIR): Likewise. * src/internal.h (_): Likewise. * src/libvirt.c (virInitialize): Likewise. * src/lxc/lxc_conf.h (LXC_CONFIG_DIR, LXC_STATE_DIR, LXC_LOG_DIR): Likewise. * src/lxc/lxc_conf.c (lxcCapsInit, lxcLoadDriverConfig): Likewise. * src/network/bridge_driver.c (NETWORK_PID_DIR) (NETWORK_STATE_DIR, DNSMASQ_STATE_DIR, networkStartup): Likewise. * src/nwfilter/nwfilter_driver.c (nwfilterDriverStartup): Likewise. * src/qemu/qemu_conf.c (qemudLoadDriverConfig): Likewise. * src/qemu/qemu_driver.c (qemudStartup): Likewise. * src/remote/remote_driver.h (LIBVIRTD_PRIV_UNIX_SOCKET) (LIBVIRTD_PRIV_UNIX_SOCKET_RO, LIBVIRTD_CONFIGURATION_FILE) (LIBVIRT_PKI_DIR): Likewise. * src/secret/secret_driver.c (secretDriverStartup): Likewise. * src/security/security_apparmor.c (VIRT_AA_HELPER): Likewise. * src/security/virt-aa-helper.c (main): Likewise. * src/storage/storage_backend_disk.c (PARTHELPER): Likewise. * src/storage/storage_driver.c (storageDriverStartup): Likewise. * src/uml/uml_driver.c (TEMPDIR, umlStartup): Likewise. * src/util/hooks.c (LIBVIRT_HOOK_DIR): Likewise. * tools/virsh.c (main): Likewise. * docs/hooks.html.in: Likewise.
2010-11-16 14:54:17 +00:00
#include "configmake.h"
#include "virnetdevtap.h"
#include "virnodesuspend.h"
#include "virprocess.h"
#include "viruri.h"
#include "virstring.h"
#include "viraccessapicheck.h"
2008-11-19 16:58:23 +00:00
#define VIR_FROM_THIS VIR_FROM_UML
VIR_LOG_INIT("uml.uml_driver");
typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
struct _umlDomainObjPrivate {
int monitor;
int monitorWatch;
};
static int umlProcessAutoDestroyInit(struct uml_driver *driver);
static void umlProcessAutoDestroyRun(struct uml_driver *driver,
virConnectPtr conn);
static void umlProcessAutoDestroyShutdown(struct uml_driver *driver);
static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
virDomainObjPtr vm,
virConnectPtr conn);
static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
virDomainObjPtr vm);
static int umlStateCleanup(void);
2008-11-19 16:58:23 +00:00
static void *umlDomainObjPrivateAlloc(void)
{
umlDomainObjPrivatePtr priv;
if (VIR_ALLOC(priv) < 0)
return NULL;
priv->monitor = -1;
priv->monitorWatch = -1;
return priv;
}
static void umlDomainObjPrivateFree(void *data)
{
umlDomainObjPrivatePtr priv = data;
VIR_FREE(priv);
}
static void umlDriverLock(struct uml_driver *driver)
{
2009-01-15 19:56:05 +00:00
virMutexLock(&driver->lock);
}
static void umlDriverUnlock(struct uml_driver *driver)
{
2009-01-15 19:56:05 +00:00
virMutexUnlock(&driver->lock);
}
2008-11-19 16:58:23 +00:00
static int umlOpenMonitor(struct uml_driver *driver,
2008-11-19 16:58:23 +00:00
virDomainObjPtr vm);
static int umlReadPidFile(struct uml_driver *driver,
2008-11-19 16:58:23 +00:00
virDomainObjPtr vm);
static void umlDomainEventQueue(struct uml_driver *driver,
virObjectEventPtr event);
2008-11-19 16:58:23 +00:00
static int umlStartVMDaemon(virConnectPtr conn,
struct uml_driver *driver,
virDomainObjPtr vm,
bool autoDestroy);
2008-11-19 16:58:23 +00:00
static void umlShutdownVMDaemon(struct uml_driver *driver,
virDomainObjPtr vm,
virDomainShutoffReason reason);
2008-11-19 16:58:23 +00:00
static int umlMonitorCommand(const struct uml_driver *driver,
const virDomainObj *vm,
const char *cmd,
char **reply);
2008-11-19 16:58:23 +00:00
static struct uml_driver *uml_driver;
2008-11-19 16:58:23 +00:00
nwfilter: fix crash during filter define when lxc driver failed startup The meat of this patch is just moving the calls to virNWFilterRegisterCallbackDriver from each hypervisor's "register" function into its "initialize" function. The rest is just code movement to allow that, and a new virNWFilterUnRegisterCallbackDriver function to undo what the register function does. The long explanation: There is an array in nwfilter called callbackDrvArray that has pointers to a table of functions for each hypervisor driver that are called by nwfilter. One of those function pointers is to a function that will lock the hypervisor driver. Entries are added to the table by calling each driver's "register" function, which happens quite early in libvirtd's startup. Sometime later, each driver's "initialize" function is called. This function allocates a driver object and stores a pointer to it in a static variable that was previously initialized to NULL. (and here's the important part...) If the "initialize" function fails, the driver object is freed, and that pointer set back to NULL (but the entry in nwfilter's callbackDrvArray is still there). When the "lock the driver" function mentioned above is called, it assumes that the driver was successfully loaded, so it blindly tries to call virMutexLock on "driver->lock". BUT, if the initialize never happened, or if it failed, "driver" is NULL. And it just happens that "lock" is always the first field in driver so it is also NULL. Boom. To fix this, the call to virNWFilterRegisterCallbackDriver for each driver shouldn't be called until the end of its (*already guaranteed successful*) "initialize" function, not during its "register" function (which is currently the case). This implies that there should also be a virNWFilterUnregisterCallbackDriver() function that is called in a driver's "shutdown" function (although in practice, that function is currently never called).
2012-08-09 06:18:23 +00:00
static int
umlVMFilterRebuild(virDomainObjListIterator iter, void *data)
nwfilter: fix crash during filter define when lxc driver failed startup The meat of this patch is just moving the calls to virNWFilterRegisterCallbackDriver from each hypervisor's "register" function into its "initialize" function. The rest is just code movement to allow that, and a new virNWFilterUnRegisterCallbackDriver function to undo what the register function does. The long explanation: There is an array in nwfilter called callbackDrvArray that has pointers to a table of functions for each hypervisor driver that are called by nwfilter. One of those function pointers is to a function that will lock the hypervisor driver. Entries are added to the table by calling each driver's "register" function, which happens quite early in libvirtd's startup. Sometime later, each driver's "initialize" function is called. This function allocates a driver object and stores a pointer to it in a static variable that was previously initialized to NULL. (and here's the important part...) If the "initialize" function fails, the driver object is freed, and that pointer set back to NULL (but the entry in nwfilter's callbackDrvArray is still there). When the "lock the driver" function mentioned above is called, it assumes that the driver was successfully loaded, so it blindly tries to call virMutexLock on "driver->lock". BUT, if the initialize never happened, or if it failed, "driver" is NULL. And it just happens that "lock" is always the first field in driver so it is also NULL. Boom. To fix this, the call to virNWFilterRegisterCallbackDriver for each driver shouldn't be called until the end of its (*already guaranteed successful*) "initialize" function, not during its "register" function (which is currently the case). This implies that there should also be a virNWFilterUnregisterCallbackDriver() function that is called in a driver's "shutdown" function (although in practice, that function is currently never called).
2012-08-09 06:18:23 +00:00
{
return virDomainObjListForEach(uml_driver->domains, iter, data);
nwfilter: fix crash during filter define when lxc driver failed startup The meat of this patch is just moving the calls to virNWFilterRegisterCallbackDriver from each hypervisor's "register" function into its "initialize" function. The rest is just code movement to allow that, and a new virNWFilterUnRegisterCallbackDriver function to undo what the register function does. The long explanation: There is an array in nwfilter called callbackDrvArray that has pointers to a table of functions for each hypervisor driver that are called by nwfilter. One of those function pointers is to a function that will lock the hypervisor driver. Entries are added to the table by calling each driver's "register" function, which happens quite early in libvirtd's startup. Sometime later, each driver's "initialize" function is called. This function allocates a driver object and stores a pointer to it in a static variable that was previously initialized to NULL. (and here's the important part...) If the "initialize" function fails, the driver object is freed, and that pointer set back to NULL (but the entry in nwfilter's callbackDrvArray is still there). When the "lock the driver" function mentioned above is called, it assumes that the driver was successfully loaded, so it blindly tries to call virMutexLock on "driver->lock". BUT, if the initialize never happened, or if it failed, "driver" is NULL. And it just happens that "lock" is always the first field in driver so it is also NULL. Boom. To fix this, the call to virNWFilterRegisterCallbackDriver for each driver shouldn't be called until the end of its (*already guaranteed successful*) "initialize" function, not during its "register" function (which is currently the case). This implies that there should also be a virNWFilterUnregisterCallbackDriver() function that is called in a driver's "shutdown" function (although in practice, that function is currently never called).
2012-08-09 06:18:23 +00:00
}
static void
umlVMDriverLock(void)
{
umlDriverLock(uml_driver);
}
static void
umlVMDriverUnlock(void)
{
umlDriverUnlock(uml_driver);
}
static virNWFilterCallbackDriver umlCallbackDriver = {
.name = "UML",
.vmFilterRebuild = umlVMFilterRebuild,
.vmDriverLock = umlVMDriverLock,
.vmDriverUnlock = umlVMDriverUnlock,
};
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
struct umlAutostartData {
struct uml_driver *driver;
virConnectPtr conn;
};
static int
umlAutostartDomain(virDomainObjPtr vm,
void *opaque)
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
{
const struct umlAutostartData *data = opaque;
int ret = 0;
virObjectLock(vm);
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
if (vm->autostart &&
!virDomainObjIsActive(vm)) {
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
virResetLastError();
ret = umlStartVMDaemon(data->conn, data->driver, vm, false);
virDomainAuditStart(vm, "booted", ret >= 0);
if (ret < 0) {
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
virErrorPtr err = virGetLastError();
VIR_ERROR(_("Failed to autostart VM '%s': %s"),
vm->def->name, err ? err->message : _("unknown error"));
} else {
virObjectEventPtr event =
virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
if (event)
umlDomainEventQueue(data->driver, event);
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
}
}
virObjectUnlock(vm);
return ret;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
}
2008-11-19 16:58:23 +00:00
static void
umlAutostartConfigs(struct uml_driver *driver)
{
/* XXX: Figure out a better way todo this. The domain
* startup code needs a connection handle in order
* to lookup the bridge associated with a virtual
* network
*/
virConnectPtr conn = virConnectOpen(driver->privileged ?
"uml:///system" :
"uml:///session");
/* Ignoring NULL conn which is mostly harmless here */
2008-11-19 16:58:23 +00:00
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
struct umlAutostartData data = { driver, conn };
umlDriverLock(driver);
virDomainObjListForEach(driver->domains, umlAutostartDomain, &data);
umlDriverUnlock(driver);
virObjectUnref(conn);
2008-11-19 16:58:23 +00:00
}
static int
umlIdentifyOneChrPTY(struct uml_driver *driver,
2008-11-19 16:58:23 +00:00
virDomainObjPtr dom,
virDomainChrDefPtr def,
const char *dev)
{
char *cmd;
char *res = NULL;
int retries = 0;
if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0)
2008-11-19 16:58:23 +00:00
return -1;
requery:
if (umlMonitorCommand(driver, dom, cmd, &res) < 0)
return -1;
2008-11-19 16:58:23 +00:00
if (res && STRPREFIX(res, "pts:")) {
domain_conf: split source data out from ChrDef This opens up the possibility of reusing the smaller ChrSourceDef for both qemu monitor and a passthrough smartcard device. * src/conf/domain_conf.h (_virDomainChrDef): Factor host details... (_virDomainChrSourceDef): ...into new struct. (virDomainChrSourceDefFree): New prototype. * src/conf/domain_conf.c (virDomainChrDefFree) (virDomainChrDefParseXML, virDomainChrDefFormat): Split... (virDomainChrSourceDefClear, virDomainChrSourceDefFree) (virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat): ...into new functions. (virDomainChrDefParseTargetXML): Update clients to reflect type split. * src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel) (virVMXFormatSerial, virVMXFormatParallel): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise. * src/xen/xend_internal.c (xenDaemonParseSxprChar) (xenDaemonFormatSxprChr): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial) (vboxAttachParallel): Likewise. * src/security/security_dac.c (virSecurityDACSetChardevLabel) (virSecurityDACSetChardevCallback) (virSecurityDACRestoreChardevLabel) (virSecurityDACRestoreChardevCallback): Likewise. * src/security/security_selinux.c (SELinuxSetSecurityChardevLabel) (SELinuxSetSecurityChardevCallback) (SELinuxRestoreSecurityChardevLabel) (SELinuxSetSecurityChardevCallback): Likewise. * src/security/virt-aa-helper.c (get_files): Likewise. * src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole): Likewise. * src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise. * src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY) (umlDomainOpenConsole): Likewise. * src/qemu/qemu_command.c (qemuBuildChrChardevStr) (qemuBuildChrArgStr, qemuBuildCommandLine) (qemuParseCommandLineChr): Likewise. * src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat) (qemuDomainObjPrivateXMLParse): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor) (qemudFindCharDevicePTYs, qemuPrepareChardevDevice) (qemuPrepareMonitorChr, qemudShutdownVMDaemon) (qemuDomainOpenConsole): Likewise. * src/qemu/qemu_command.h (qemuBuildChrChardevStr) (qemuBuildChrArgStr): Delete, now that they are static. * src/libvirt_private.syms (domain_conf.h): New exports. * cfg.mk (useless_free_options): Update list. * tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update tests.
2011-01-07 22:45:01 +00:00
VIR_FREE(def->source.data.file.path);
if (VIR_STRDUP(def->source.data.file.path, res + 4) < 0) {
2008-11-19 16:58:23 +00:00
VIR_FREE(res);
VIR_FREE(cmd);
return -1;
}
} else if (!res || STRPREFIX(res, "pts")) {
2008-11-19 16:58:23 +00:00
/* It can take a while to startup, so retry for
2012-10-11 16:31:20 +00:00
up to 5 seconds */
2008-11-19 16:58:23 +00:00
/* XXX should do this in a better non-blocking
way somehow ...perhaps register a timer */
if (retries++ < 50) {
VIR_FREE(res);
2008-11-19 16:58:23 +00:00
usleep(1000*10);
goto requery;
}
}
VIR_FREE(cmd);
VIR_FREE(res);
return 0;
}
static int
umlIdentifyChrPTY(struct uml_driver *driver,
2008-11-19 16:58:23 +00:00
virDomainObjPtr dom)
{
size_t i;
2008-11-19 16:58:23 +00:00
for (i = 0; i < dom->def->nconsoles; i++)
if (dom->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
if (umlIdentifyOneChrPTY(driver, dom,
dom->def->consoles[i], "con") < 0)
2008-11-19 16:58:23 +00:00
return -1;
for (i = 0; i < dom->def->nserials; i++)
domain_conf: split source data out from ChrDef This opens up the possibility of reusing the smaller ChrSourceDef for both qemu monitor and a passthrough smartcard device. * src/conf/domain_conf.h (_virDomainChrDef): Factor host details... (_virDomainChrSourceDef): ...into new struct. (virDomainChrSourceDefFree): New prototype. * src/conf/domain_conf.c (virDomainChrDefFree) (virDomainChrDefParseXML, virDomainChrDefFormat): Split... (virDomainChrSourceDefClear, virDomainChrSourceDefFree) (virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat): ...into new functions. (virDomainChrDefParseTargetXML): Update clients to reflect type split. * src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel) (virVMXFormatSerial, virVMXFormatParallel): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise. * src/xen/xend_internal.c (xenDaemonParseSxprChar) (xenDaemonFormatSxprChr): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial) (vboxAttachParallel): Likewise. * src/security/security_dac.c (virSecurityDACSetChardevLabel) (virSecurityDACSetChardevCallback) (virSecurityDACRestoreChardevLabel) (virSecurityDACRestoreChardevCallback): Likewise. * src/security/security_selinux.c (SELinuxSetSecurityChardevLabel) (SELinuxSetSecurityChardevCallback) (SELinuxRestoreSecurityChardevLabel) (SELinuxSetSecurityChardevCallback): Likewise. * src/security/virt-aa-helper.c (get_files): Likewise. * src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole): Likewise. * src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise. * src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY) (umlDomainOpenConsole): Likewise. * src/qemu/qemu_command.c (qemuBuildChrChardevStr) (qemuBuildChrArgStr, qemuBuildCommandLine) (qemuParseCommandLineChr): Likewise. * src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat) (qemuDomainObjPrivateXMLParse): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor) (qemudFindCharDevicePTYs, qemuPrepareChardevDevice) (qemuPrepareMonitorChr, qemudShutdownVMDaemon) (qemuDomainOpenConsole): Likewise. * src/qemu/qemu_command.h (qemuBuildChrChardevStr) (qemuBuildChrArgStr): Delete, now that they are static. * src/libvirt_private.syms (domain_conf.h): New exports. * cfg.mk (useless_free_options): Update list. * tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update tests.
2011-01-07 22:45:01 +00:00
if (dom->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
umlIdentifyOneChrPTY(driver, dom,
2008-11-19 16:58:23 +00:00
dom->def->serials[i], "ssl") < 0)
return -1;
return 0;
}
static void
umlInotifyEvent(int watch,
int fd,
int events ATTRIBUTE_UNUSED,
void *data)
{
char buf[1024];
struct inotify_event e;
2008-11-19 16:58:23 +00:00
int got;
char *tmp, *name;
struct uml_driver *driver = data;
virDomainObjPtr dom;
virObjectEventPtr event = NULL;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
2008-11-19 16:58:23 +00:00
if (watch != driver->inotifyWatch)
goto cleanup;
2008-11-19 16:58:23 +00:00
reread:
2008-11-19 16:58:23 +00:00
got = read(fd, buf, sizeof(buf));
if (got == -1) {
if (errno == EINTR)
goto reread;
goto cleanup;
2008-11-19 16:58:23 +00:00
}
tmp = buf;
while (got) {
if (got < sizeof(e))
goto cleanup; /* bad */
2008-11-19 16:58:23 +00:00
memcpy(&e, tmp, sizeof(e));
tmp += sizeof(e);
got -= sizeof(e);
2008-11-19 16:58:23 +00:00
if (got < e.len)
goto cleanup;
2008-11-19 16:58:23 +00:00
tmp += e.len;
got -= e.len;
2008-11-19 16:58:23 +00:00
name = (char *)&(e.name);
2008-11-19 16:58:23 +00:00
dom = virDomainObjListFindByName(driver->domains, name);
2008-11-19 16:58:23 +00:00
if (!dom)
2008-11-19 16:58:23 +00:00
continue;
if (e.mask & IN_DELETE) {
VIR_DEBUG("Got inotify domain shutdown '%s'", name);
if (!virDomainObjIsActive(dom)) {
virDomainObjEndAPI(&dom);
2008-11-19 16:58:23 +00:00
continue;
}
umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
virDomainAuditStop(dom, "shutdown");
event = virDomainEventLifecycleNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
if (!dom->persistent)
virDomainObjListRemove(driver->domains, dom);
} else if (e.mask & (IN_CREATE | IN_MODIFY)) {
VIR_DEBUG("Got inotify domain startup '%s'", name);
if (virDomainObjIsActive(dom)) {
virDomainObjEndAPI(&dom);
2008-11-19 16:58:23 +00:00
continue;
}
if (umlReadPidFile(driver, dom) < 0) {
virDomainObjEndAPI(&dom);
2008-11-19 16:58:23 +00:00
continue;
}
dom->def->id = driver->nextvmid++;
if (!driver->nactive && driver->inhibitCallback)
driver->inhibitCallback(true, driver->inhibitOpaque);
driver->nactive++;
virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
VIR_DOMAIN_RUNNING_BOOTED);
2008-11-19 16:58:23 +00:00
if (umlOpenMonitor(driver, dom) < 0) {
VIR_WARN("Could not open monitor for new domain");
umlShutdownVMDaemon(driver, dom,
VIR_DOMAIN_SHUTOFF_FAILED);
virDomainAuditStop(dom, "failed");
event = virDomainEventLifecycleNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_FAILED);
if (!dom->persistent)
virDomainObjListRemove(driver->domains, dom);
} else if (umlIdentifyChrPTY(driver, dom) < 0) {
VIR_WARN("Could not identify character devices for new domain");
umlShutdownVMDaemon(driver, dom,
VIR_DOMAIN_SHUTOFF_FAILED);
virDomainAuditStop(dom, "failed");
event = virDomainEventLifecycleNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_FAILED);
if (!dom->persistent)
virDomainObjListRemove(driver->domains, dom);
}
2008-11-19 16:58:23 +00:00
}
virDomainObjEndAPI(&dom);
if (event) {
umlDomainEventQueue(driver, event);
event = NULL;
}
2008-11-19 16:58:23 +00:00
}
cleanup:
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
}
static int
umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
maint: avoid 'const fooPtr' in domain_conf 'const fooPtr' is the same as 'foo * const' (the pointer won't change, but it's contents can). But in general, if an interface is trying to be const-correct, it should be using 'const foo *' (the pointer is to data that can't be changed). Fix up offenders in src/conf/domain_conf, and their fallout. Several things to note: virObjectLock() requires a non-const argument; if this were C++, we could treat the locking field as 'mutable' and allow locking an otherwise 'const' object, but that is a more invasive change, so I instead dropped attempts to be const-correct on domain lookup. virXMLPropString and friends require a non-const xmlNodePtr - this is because libxml2 is not a const-correct library. We could make the src/util/virxml wrappers cast away const, but I figured it was easier to not try to mark xmlNodePtr as const. Finally, virDomainDeviceDefCopy was a rather hard conversion - it calls virDomainDeviceDefPostParse, which in turn in the xen driver was actually modifying the domain outside of the current device being visited. We should not be adding a device on the first per-device callback, but waiting until after all per-device callbacks are complete. * src/conf/domain_conf.h (virDomainObjListFindByID) (virDomainObjListFindByUUID, virDomainObjListFindByName) (virDomainObjAssignDef, virDomainObjListAdd): Drop attempt at const. (virDomainDeviceDefCopy): Use intended type. (virDomainDeviceDefParse, virDomainDeviceDefPostParseCallback) (virDomainVideoDefaultType, virDomainVideoDefaultRAM) (virDomainChrGetDomainPtrs): Make const-correct. * src/conf/domain_conf.c (virDomainObjListFindByID) (virDomainObjListFindByUUID, virDomainObjListFindByName) (virDomainDeviceDefCopy, virDomainObjListAdd) (virDomainObjAssignDef, virDomainHostdevSubsysUsbDefParseXML) (virDomainHostdevSubsysPciOrigStatesDefParseXML) (virDomainHostdevSubsysPciDefParseXML) (virDomainHostdevSubsysScsiDefParseXML) (virDomainControllerModelTypeFromString) (virDomainTPMDefParseXML, virDomainTimerDefParseXML) (virDomainSoundCodecDefParseXML, virDomainSoundDefParseXML) (virDomainWatchdogDefParseXML, virDomainRNGDefParseXML) (virDomainMemballoonDefParseXML, virDomainNVRAMDefParseXML) (virSysinfoParseXML, virDomainVideoAccelDefParseXML) (virDomainVideoDefParseXML, virDomainHostdevDefParseXML) (virDomainRedirdevDefParseXML) (virDomainRedirFilterUsbDevDefParseXML) (virDomainRedirFilterDefParseXML, virDomainIdMapEntrySort) (virDomainIdmapDefParseXML, virDomainVcpuPinDefParseXML) (virDiskNameToBusDeviceIndex, virDomainDeviceDefCopy) (virDomainVideoDefaultType, virDomainHostdevAssignAddress) (virDomainDeviceDefPostParseInternal, virDomainDeviceDefPostParse) (virDomainChrGetDomainPtrs, virDomainControllerSCSINextUnit) (virDomainSCSIDriveAddressIsUsed) (virDomainDriveAddressIsUsedByDisk) (virDomainDriveAddressIsUsedByHostdev): Fix fallout. * src/openvz/openvz_driver.c (openvzDomainDeviceDefPostParse): Likewise. * src/libxl/libxl_domain.c (libxlDomainDeviceDefPostParse): Likewise. * src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse) (qemuDomainDefaultNetModel): Likewise. * src/lxc/lxc_domain.c (virLXCDomainDeviceDefPostParse): Likewise. * src/uml/uml_driver.c (umlDomainDeviceDefPostParse): Likewise. * src/xen/xen_driver.c (xenDomainDeviceDefPostParse): Split... (xenDomainDefPostParse): ...since per-device callback is not the time to be adding a device. Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-08 15:08:25 +00:00
const virDomainDef *def ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_UML;
/* forbid capabilities mode hostdev in this kind of hypervisor */
if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hostdev mode 'capabilities' is not "
"supported in %s"),
virDomainVirtTypeToString(def->virtType));
return -1;
}
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
return -1;
return 0;
}
static int
umlDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
/* memory hotplug tunables are not supported by this driver */
if (virDomainDefCheckUnsupportedMemoryHotplug(def) < 0)
return -1;
return 0;
}
virDomainDefParserConfig umlDriverDomainDefParserConfig = {
.devicesPostParseCallback = umlDomainDeviceDefPostParse,
.domainPostParseCallback = umlDomainDefPostParse,
};
2008-11-19 16:58:23 +00:00
/**
* umlStartup:
*
* Initialization function for the Uml daemon
*/
static int
umlStateInitialize(bool privileged,
virStateInhibitCallback callback,
void *opaque)
{
2008-11-19 16:58:23 +00:00
char *base = NULL;
2009-01-22 19:41:48 +00:00
char *userdir = NULL;
2008-11-19 16:58:23 +00:00
virDomainXMLPrivateDataCallbacks privcb = {
.alloc = umlDomainObjPrivateAlloc,
.free = umlDomainObjPrivateFree,
};
2008-11-19 16:58:23 +00:00
if (VIR_ALLOC(uml_driver) < 0)
return -1;
uml_driver->privileged = privileged;
uml_driver->inhibitCallback = callback;
uml_driver->inhibitOpaque = opaque;
2009-01-15 19:56:05 +00:00
if (virMutexInit(&uml_driver->lock) < 0) {
VIR_FREE(uml_driver);
return -1;
}
umlDriverLock(uml_driver);
2008-11-19 16:58:23 +00:00
/* Don't have a dom0 so start from 1 */
uml_driver->nextvmid = 1;
uml_driver->inotifyWatch = -1;
2008-11-19 16:58:23 +00:00
if (!(uml_driver->domains = virDomainObjListNew()))
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
goto error;
uml_driver->domainEventState = virObjectEventStateNew();
if (!uml_driver->domainEventState)
goto error;
userdir = virGetUserDirectory();
2009-01-22 19:41:48 +00:00
if (!userdir)
goto error;
2008-11-19 16:58:23 +00:00
if (privileged) {
2008-12-23 13:03:29 +00:00
if (virAsprintf(&uml_driver->logDir,
maint: use gnulib configmake rather than open-coding things * bootstrap.conf (gnulib_modules): Add configmake. * daemon/Makefile.am (libvirtd_CFLAGS): Drop defines provided by gnulib. * src/Makefile.am (INCLUDES): Likewise. * tests/Makefile.am (INCLUDES): Likewise. * tools/Makefile.am (virsh_CFLAGS): Likewise. * daemon/libvirtd.c (qemudInitPaths, usage, main): Update clients. * src/cpu/cpu_map.c (CPUMAPFILE): Likewise. * src/driver.c (DEFAULT_DRIVER_DIR): Likewise. * src/internal.h (_): Likewise. * src/libvirt.c (virInitialize): Likewise. * src/lxc/lxc_conf.h (LXC_CONFIG_DIR, LXC_STATE_DIR, LXC_LOG_DIR): Likewise. * src/lxc/lxc_conf.c (lxcCapsInit, lxcLoadDriverConfig): Likewise. * src/network/bridge_driver.c (NETWORK_PID_DIR) (NETWORK_STATE_DIR, DNSMASQ_STATE_DIR, networkStartup): Likewise. * src/nwfilter/nwfilter_driver.c (nwfilterDriverStartup): Likewise. * src/qemu/qemu_conf.c (qemudLoadDriverConfig): Likewise. * src/qemu/qemu_driver.c (qemudStartup): Likewise. * src/remote/remote_driver.h (LIBVIRTD_PRIV_UNIX_SOCKET) (LIBVIRTD_PRIV_UNIX_SOCKET_RO, LIBVIRTD_CONFIGURATION_FILE) (LIBVIRT_PKI_DIR): Likewise. * src/secret/secret_driver.c (secretDriverStartup): Likewise. * src/security/security_apparmor.c (VIRT_AA_HELPER): Likewise. * src/security/virt-aa-helper.c (main): Likewise. * src/storage/storage_backend_disk.c (PARTHELPER): Likewise. * src/storage/storage_driver.c (storageDriverStartup): Likewise. * src/uml/uml_driver.c (TEMPDIR, umlStartup): Likewise. * src/util/hooks.c (LIBVIRT_HOOK_DIR): Likewise. * tools/virsh.c (main): Likewise. * docs/hooks.html.in: Likewise.
2010-11-16 14:54:17 +00:00
"%s/log/libvirt/uml", LOCALSTATEDIR) == -1)
2008-11-19 16:58:23 +00:00
goto out_of_memory;
if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
goto error;
if (virAsprintf(&uml_driver->monitorDir,
maint: use gnulib configmake rather than open-coding things * bootstrap.conf (gnulib_modules): Add configmake. * daemon/Makefile.am (libvirtd_CFLAGS): Drop defines provided by gnulib. * src/Makefile.am (INCLUDES): Likewise. * tests/Makefile.am (INCLUDES): Likewise. * tools/Makefile.am (virsh_CFLAGS): Likewise. * daemon/libvirtd.c (qemudInitPaths, usage, main): Update clients. * src/cpu/cpu_map.c (CPUMAPFILE): Likewise. * src/driver.c (DEFAULT_DRIVER_DIR): Likewise. * src/internal.h (_): Likewise. * src/libvirt.c (virInitialize): Likewise. * src/lxc/lxc_conf.h (LXC_CONFIG_DIR, LXC_STATE_DIR, LXC_LOG_DIR): Likewise. * src/lxc/lxc_conf.c (lxcCapsInit, lxcLoadDriverConfig): Likewise. * src/network/bridge_driver.c (NETWORK_PID_DIR) (NETWORK_STATE_DIR, DNSMASQ_STATE_DIR, networkStartup): Likewise. * src/nwfilter/nwfilter_driver.c (nwfilterDriverStartup): Likewise. * src/qemu/qemu_conf.c (qemudLoadDriverConfig): Likewise. * src/qemu/qemu_driver.c (qemudStartup): Likewise. * src/remote/remote_driver.h (LIBVIRTD_PRIV_UNIX_SOCKET) (LIBVIRTD_PRIV_UNIX_SOCKET_RO, LIBVIRTD_CONFIGURATION_FILE) (LIBVIRT_PKI_DIR): Likewise. * src/secret/secret_driver.c (secretDriverStartup): Likewise. * src/security/security_apparmor.c (VIRT_AA_HELPER): Likewise. * src/security/virt-aa-helper.c (main): Likewise. * src/storage/storage_backend_disk.c (PARTHELPER): Likewise. * src/storage/storage_driver.c (storageDriverStartup): Likewise. * src/uml/uml_driver.c (TEMPDIR, umlStartup): Likewise. * src/util/hooks.c (LIBVIRT_HOOK_DIR): Likewise. * tools/virsh.c (main): Likewise. * docs/hooks.html.in: Likewise.
2010-11-16 14:54:17 +00:00
"%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
goto out_of_memory;
2008-11-19 16:58:23 +00:00
} else {
base = virGetUserConfigDirectory();
if (!base)
goto error;
2009-01-22 19:41:48 +00:00
2008-12-23 13:03:29 +00:00
if (virAsprintf(&uml_driver->logDir,
"%s/uml/log", base) == -1)
2008-11-19 16:58:23 +00:00
goto out_of_memory;
if (virAsprintf(&uml_driver->monitorDir,
"%s/.uml", userdir) == -1)
goto out_of_memory;
}
2008-11-19 16:58:23 +00:00
/* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
2008-11-19 16:58:23 +00:00
* /etc/libvirt/uml/... (system).
*/
2008-12-23 13:03:29 +00:00
if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
2008-11-19 16:58:23 +00:00
goto out_of_memory;
2008-12-23 13:03:29 +00:00
if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
2008-11-19 16:58:23 +00:00
goto out_of_memory;
VIR_FREE(base);
if ((uml_driver->caps = umlCapsInit()) == NULL)
goto out_of_memory;
if (!(uml_driver->xmlopt = virDomainXMLOptionNew(&umlDriverDomainDefParserConfig,
&privcb, NULL)))
goto error;
2008-11-19 16:58:23 +00:00
if ((uml_driver->inotifyFD = inotify_init()) < 0) {
VIR_ERROR(_("cannot initialize inotify"));
goto error;
2008-11-19 16:58:23 +00:00
}
if (virFileMakePath(uml_driver->monitorDir) < 0) {
char ebuf[1024];
VIR_ERROR(_("Failed to create monitor directory %s: %s"),
uml_driver->monitorDir,
virStrerror(errno, ebuf, sizeof(ebuf)));
goto error;
2008-11-19 16:58:23 +00:00
}
VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
if (inotify_add_watch(uml_driver->inotifyFD,
uml_driver->monitorDir,
IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
char ebuf[1024];
VIR_ERROR(_("Failed to create inotify watch on %s: %s"),
uml_driver->monitorDir,
virStrerror(errno, ebuf, sizeof(ebuf)));
goto error;
2008-11-19 16:58:23 +00:00
}
if ((uml_driver->inotifyWatch =
virEventAddHandle(uml_driver->inotifyFD, POLLIN,
umlInotifyEvent, uml_driver, NULL)) < 0)
goto error;
2008-11-19 16:58:23 +00:00
if (umlProcessAutoDestroyInit(uml_driver) < 0)
goto error;
if (virDomainObjListLoadAllConfigs(uml_driver->domains,
uml_driver->configDir,
uml_driver->autostartDir, 0,
uml_driver->caps,
uml_driver->xmlopt,
NULL, NULL) < 0)
goto error;
umlDriverUnlock(uml_driver);
2009-01-22 19:41:48 +00:00
VIR_FREE(userdir);
nwfilter: fix crash during filter define when lxc driver failed startup The meat of this patch is just moving the calls to virNWFilterRegisterCallbackDriver from each hypervisor's "register" function into its "initialize" function. The rest is just code movement to allow that, and a new virNWFilterUnRegisterCallbackDriver function to undo what the register function does. The long explanation: There is an array in nwfilter called callbackDrvArray that has pointers to a table of functions for each hypervisor driver that are called by nwfilter. One of those function pointers is to a function that will lock the hypervisor driver. Entries are added to the table by calling each driver's "register" function, which happens quite early in libvirtd's startup. Sometime later, each driver's "initialize" function is called. This function allocates a driver object and stores a pointer to it in a static variable that was previously initialized to NULL. (and here's the important part...) If the "initialize" function fails, the driver object is freed, and that pointer set back to NULL (but the entry in nwfilter's callbackDrvArray is still there). When the "lock the driver" function mentioned above is called, it assumes that the driver was successfully loaded, so it blindly tries to call virMutexLock on "driver->lock". BUT, if the initialize never happened, or if it failed, "driver" is NULL. And it just happens that "lock" is always the first field in driver so it is also NULL. Boom. To fix this, the call to virNWFilterRegisterCallbackDriver for each driver shouldn't be called until the end of its (*already guaranteed successful*) "initialize" function, not during its "register" function (which is currently the case). This implies that there should also be a virNWFilterUnregisterCallbackDriver() function that is called in a driver's "shutdown" function (although in practice, that function is currently never called).
2012-08-09 06:18:23 +00:00
virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
2008-11-19 16:58:23 +00:00
return 0;
out_of_memory:
VIR_ERROR(_("umlStartup: out of memory"));
error:
2009-01-22 19:41:48 +00:00
VIR_FREE(userdir);
2008-11-19 16:58:23 +00:00
VIR_FREE(base);
umlDriverUnlock(uml_driver);
umlStateCleanup();
2008-11-19 16:58:23 +00:00
return -1;
}
/**
* umlStateAutoStart:
*
* Function to autostart the Uml daemons
*/
static void
umlStateAutoStart(void)
{
if (!uml_driver)
return;
umlAutostartConfigs(uml_driver);
}
static void umlNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
struct uml_driver *driver = opaque;
if (newVM) {
virObjectEventPtr event =
virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_DEFINED,
VIR_DOMAIN_EVENT_DEFINED_ADDED);
if (event)
umlDomainEventQueue(driver, event);
}
}
2008-11-19 16:58:23 +00:00
/**
* umlStateReload:
2008-11-19 16:58:23 +00:00
*
* Function to restart the Uml daemon, it will recheck the configuration
* files and update its state and the networking
*/
static int
umlStateReload(void)
{
2008-11-19 16:58:23 +00:00
if (!uml_driver)
return 0;
umlDriverLock(uml_driver);
virDomainObjListLoadAllConfigs(uml_driver->domains,
uml_driver->configDir,
uml_driver->autostartDir, 0,
uml_driver->caps,
uml_driver->xmlopt,
umlNotifyLoadDomain, uml_driver);
umlDriverUnlock(uml_driver);
2008-11-19 16:58:23 +00:00
return 0;
}
static int
umlShutdownOneVM(virDomainObjPtr dom, void *opaque)
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
{
struct uml_driver *driver = opaque;
virObjectLock(dom);
if (virDomainObjIsActive(dom)) {
umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
virDomainAuditStop(dom, "shutdown");
}
virObjectUnlock(dom);
return 0;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
}
2008-11-19 16:58:23 +00:00
/**
* umlStateCleanup:
2008-11-19 16:58:23 +00:00
*
* Shutdown the Uml daemon, it will stop all active domains and networks
*/
static int
umlStateCleanup(void)
{
2008-11-19 16:58:23 +00:00
if (!uml_driver)
return -1;
umlDriverLock(uml_driver);
nwfilter: fix crash during filter define when lxc driver failed startup The meat of this patch is just moving the calls to virNWFilterRegisterCallbackDriver from each hypervisor's "register" function into its "initialize" function. The rest is just code movement to allow that, and a new virNWFilterUnRegisterCallbackDriver function to undo what the register function does. The long explanation: There is an array in nwfilter called callbackDrvArray that has pointers to a table of functions for each hypervisor driver that are called by nwfilter. One of those function pointers is to a function that will lock the hypervisor driver. Entries are added to the table by calling each driver's "register" function, which happens quite early in libvirtd's startup. Sometime later, each driver's "initialize" function is called. This function allocates a driver object and stores a pointer to it in a static variable that was previously initialized to NULL. (and here's the important part...) If the "initialize" function fails, the driver object is freed, and that pointer set back to NULL (but the entry in nwfilter's callbackDrvArray is still there). When the "lock the driver" function mentioned above is called, it assumes that the driver was successfully loaded, so it blindly tries to call virMutexLock on "driver->lock". BUT, if the initialize never happened, or if it failed, "driver" is NULL. And it just happens that "lock" is always the first field in driver so it is also NULL. Boom. To fix this, the call to virNWFilterRegisterCallbackDriver for each driver shouldn't be called until the end of its (*already guaranteed successful*) "initialize" function, not during its "register" function (which is currently the case). This implies that there should also be a virNWFilterUnregisterCallbackDriver() function that is called in a driver's "shutdown" function (although in practice, that function is currently never called).
2012-08-09 06:18:23 +00:00
virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
if (uml_driver->inotifyWatch != -1)
virEventRemoveHandle(uml_driver->inotifyWatch);
VIR_FORCE_CLOSE(uml_driver->inotifyFD);
virObjectUnref(uml_driver->caps);
virObjectUnref(uml_driver->xmlopt);
2008-11-19 16:58:23 +00:00
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
/* shutdown active VMs
* XXX allow them to stay around & reconnect */
virDomainObjListForEach(uml_driver->domains, umlShutdownOneVM, uml_driver);
2008-11-19 16:58:23 +00:00
virObjectUnref(uml_driver->domains);
2008-11-19 16:58:23 +00:00
virObjectEventStateFree(uml_driver->domainEventState);
2008-11-19 16:58:23 +00:00
VIR_FREE(uml_driver->logDir);
VIR_FREE(uml_driver->configDir);
VIR_FREE(uml_driver->autostartDir);
VIR_FREE(uml_driver->monitorDir);
umlProcessAutoDestroyShutdown(uml_driver);
umlDriverUnlock(uml_driver);
2009-01-15 19:56:05 +00:00
virMutexDestroy(&uml_driver->lock);
2008-11-19 16:58:23 +00:00
VIR_FREE(uml_driver);
return 0;
}
static int umlProcessAutoDestroyInit(struct uml_driver *driver)
{
if (!(driver->autodestroy = virHashCreate(5, NULL)))
return -1;
return 0;
}
struct umlProcessAutoDestroyData {
struct uml_driver *driver;
virConnectPtr conn;
};
static void umlProcessAutoDestroyDom(void *payload,
const void *name,
void *opaque)
{
struct umlProcessAutoDestroyData *data = opaque;
virConnectPtr conn = payload;
const char *uuidstr = name;
unsigned char uuid[VIR_UUID_BUFLEN];
virDomainObjPtr dom;
virObjectEventPtr event = NULL;
VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn);
if (data->conn != conn)
return;
if (virUUIDParse(uuidstr, uuid) < 0) {
VIR_WARN("Failed to parse %s", uuidstr);
return;
}
if (!(dom = virDomainObjListFindByUUID(data->driver->domains,
uuid))) {
VIR_DEBUG("No domain object to kill");
return;
}
VIR_DEBUG("Killing domain");
umlShutdownVMDaemon(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
virDomainAuditStop(dom, "destroyed");
event = virDomainEventLifecycleNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (dom && !dom->persistent)
virDomainObjListRemove(data->driver->domains, dom);
if (dom)
virObjectUnlock(dom);
if (event)
umlDomainEventQueue(data->driver, event);
virHashRemoveEntry(data->driver->autodestroy, uuidstr);
}
/*
* Precondition: driver is locked
*/
static void umlProcessAutoDestroyRun(struct uml_driver *driver, virConnectPtr conn)
{
struct umlProcessAutoDestroyData data = {
driver, conn
};
VIR_DEBUG("conn=%p", conn);
virHashForEach(driver->autodestroy, umlProcessAutoDestroyDom, &data);
}
static void umlProcessAutoDestroyShutdown(struct uml_driver *driver)
{
virHashFree(driver->autodestroy);
}
static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
virDomainObjPtr vm,
virConnectPtr conn)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(vm->def->uuid, uuidstr);
VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn);
if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0)
return -1;
return 0;
}
static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
virDomainObjPtr vm)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(vm->def->uuid, uuidstr);
VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr);
if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0)
return -1;
return 0;
}
static int umlReadPidFile(struct uml_driver *driver,
2008-11-19 16:58:23 +00:00
virDomainObjPtr vm)
{
int rc = -1;
FILE *file;
char *pidfile = NULL;
int retries = 0;
vm->pid = -1;
2008-12-23 13:03:29 +00:00
if (virAsprintf(&pidfile, "%s/%s/pid",
driver->monitorDir, vm->def->name) < 0)
2008-11-19 16:58:23 +00:00
return -1;
reopen:
2008-11-19 16:58:23 +00:00
if (!(file = fopen(pidfile, "r"))) {
if (errno == ENOENT &&
retries++ < 50) {
usleep(1000 * 100);
goto reopen;
}
goto cleanup;
}
if (fscanf(file, "%d", &vm->pid) != 1) {
errno = EINVAL;
VIR_FORCE_FCLOSE(file);
2008-11-19 16:58:23 +00:00
goto cleanup;
}
if (VIR_FCLOSE(file) < 0)
2008-11-19 16:58:23 +00:00
goto cleanup;
rc = 0;
cleanup:
if (rc != 0)
virReportSystemError(errno,
_("failed to read pid: %s"),
pidfile);
2008-11-19 16:58:23 +00:00
VIR_FREE(pidfile);
return rc;
}
static int umlMonitorAddress(const struct uml_driver *driver,
const virDomainObj *vm,
struct sockaddr_un *addr)
{
2008-11-19 16:58:23 +00:00
char *sockname;
int retval = 0;
2008-11-19 16:58:23 +00:00
2008-12-23 13:03:29 +00:00
if (virAsprintf(&sockname, "%s/%s/mconsole",
driver->monitorDir, vm->def->name) < 0)
2008-11-19 16:58:23 +00:00
return -1;
memset(addr, 0, sizeof(*addr));
2008-11-19 16:58:23 +00:00
addr->sun_family = AF_UNIX;
if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unix path %s too long for destination"), sockname);
retval = -1;
}
2008-11-19 16:58:23 +00:00
VIR_FREE(sockname);
return retval;
2008-11-19 16:58:23 +00:00
}
static int umlOpenMonitor(struct uml_driver *driver,
virDomainObjPtr vm)
{
2008-11-19 16:58:23 +00:00
struct sockaddr_un addr;
struct stat sb;
int retries = 0;
umlDomainObjPrivatePtr priv = vm->privateData;
2008-11-19 16:58:23 +00:00
if (umlMonitorAddress(driver, vm, &addr) < 0)
2008-11-19 16:58:23 +00:00
return -1;
VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
restat:
2008-11-19 16:58:23 +00:00
if (stat(addr.sun_path, &sb) < 0) {
if (errno == ENOENT &&
retries++ < 50) {
2008-11-19 16:58:23 +00:00
usleep(1000 * 100);
goto restat;
}
return -1;
}
if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
virReportSystemError(errno,
"%s", _("cannot open socket"));
2008-11-19 16:58:23 +00:00
return -1;
}
memset(addr.sun_path, 0, sizeof(addr.sun_path));
snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
"libvirt-uml-%u", vm->pid);
VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
virReportSystemError(errno,
"%s", _("cannot bind socket"));
VIR_FORCE_CLOSE(priv->monitor);
2008-11-19 16:58:23 +00:00
return -1;
}
return 0;
}
#define MONITOR_MAGIC 0xcafebabe
#define MONITOR_BUFLEN 512
#define MONITOR_VERSION 2
struct monitor_request {
uint32_t magic;
uint32_t version;
uint32_t length;
char data[MONITOR_BUFLEN];
};
struct monitor_response {
uint32_t error;
uint32_t extra;
uint32_t length;
char data[MONITOR_BUFLEN];
};
static int umlMonitorCommand(const struct uml_driver *driver,
const virDomainObj *vm,
2008-11-19 16:58:23 +00:00
const char *cmd,
char **reply)
{
struct monitor_request req;
struct monitor_response res;
char *retdata = NULL;
int retlen = 0, ret = 0;
struct sockaddr_un addr;
unsigned int addrlen;
umlDomainObjPrivatePtr priv = vm->privateData;
2008-11-19 16:58:23 +00:00
VIR_DEBUG("Run command '%s'", cmd);
2008-11-19 16:58:23 +00:00
*reply = NULL;
if (umlMonitorAddress(driver, vm, &addr) < 0)
2008-11-19 16:58:23 +00:00
return -1;
memset(&req, 0, sizeof(req));
req.magic = MONITOR_MAGIC;
req.version = MONITOR_VERSION;
req.length = strlen(cmd);
if (req.length > (MONITOR_BUFLEN-1)) {
virReportSystemError(EINVAL,
_("cannot send too long command %s (%d bytes)"),
cmd, req.length);
2008-11-19 16:58:23 +00:00
return -1;
}
if (virStrcpyStatic(req.data, cmd) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Command %s too long for destination"), cmd);
return -1;
}
2008-11-19 16:58:23 +00:00
if (sendto(priv->monitor, &req, sizeof(req), 0,
(struct sockaddr *)&addr, sizeof(addr)) != sizeof(req)) {
virReportSystemError(errno,
_("cannot send command %s"),
cmd);
2008-11-19 16:58:23 +00:00
return -1;
}
do {
ssize_t nbytes;
2008-11-19 16:58:23 +00:00
addrlen = sizeof(addr);
nbytes = recvfrom(priv->monitor, &res, sizeof(res), 0,
(struct sockaddr *)&addr, &addrlen);
if (nbytes < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
virReportSystemError(errno, _("cannot read reply %s"), cmd);
2008-11-19 16:58:23 +00:00
goto error;
}
/* Ensure res.length is safe to read before validating its value. */
if (nbytes < offsetof(struct monitor_request, data) ||
nbytes < offsetof(struct monitor_request, data) + res.length) {
virReportSystemError(0, _("incomplete reply %s"), cmd);
goto error;
}
2008-11-19 16:58:23 +00:00
if (VIR_REALLOC_N(retdata, retlen + res.length) < 0)
2008-11-19 16:58:23 +00:00
goto error;
memcpy(retdata + retlen, res.data, res.length);
retlen += res.length - 1;
retdata[retlen] = '\0';
if (res.error)
ret = -1;
} while (res.extra);
VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
if (ret < 0)
VIR_FREE(retdata);
else
*reply = retdata;
2008-11-19 16:58:23 +00:00
return ret;
error:
2008-11-19 16:58:23 +00:00
VIR_FREE(retdata);
return -1;
}
static void umlCleanupTapDevices(virDomainObjPtr vm)
{
size_t i;
2009-06-03 11:13:33 +00:00
for (i = 0; i < vm->def->nnets; i++) {
2009-06-03 11:13:33 +00:00
virDomainNetDefPtr def = vm->def->nets[i];
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
continue;
ignore_value(virNetDevTapDelete(def->ifname,
def->backend.tap));
2009-06-03 11:13:33 +00:00
}
}
2008-11-19 16:58:23 +00:00
static int umlStartVMDaemon(virConnectPtr conn,
struct uml_driver *driver,
virDomainObjPtr vm,
bool autoDestroy)
{
int ret = -1;
2008-11-19 16:58:23 +00:00
char *logfile;
int logfd = -1;
umlDomainObjPrivatePtr priv = vm->privateData;
virCommandPtr cmd = NULL;
size_t i;
2008-11-19 16:58:23 +00:00
if (virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("VM is already active"));
2008-11-19 16:58:23 +00:00
return -1;
}
if (!vm->def->os.kernel) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("no kernel specified"));
2008-11-19 16:58:23 +00:00
return -1;
}
/* Make sure the binary we are about to try exec'ing exists.
* Technically we could catch the exec() failure, but that's
* in a sub-process so its hard to feed back a useful error
*/
if (!virFileIsExecutable(vm->def->os.kernel)) {
virReportSystemError(errno,
_("Cannot find UML kernel %s"),
vm->def->os.kernel);
2008-11-19 16:58:23 +00:00
return -1;
}
if (virFileMakePath(driver->logDir) < 0) {
virReportSystemError(errno,
_("cannot create log directory %s"),
driver->logDir);
2008-11-19 16:58:23 +00:00
return -1;
}
2008-12-23 13:03:29 +00:00
if (virAsprintf(&logfile, "%s/%s.log",
driver->logDir, vm->def->name) < 0)
2008-11-19 16:58:23 +00:00
return -1;
if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR)) < 0) {
virReportSystemError(errno,
_("failed to create logfile %s"),
logfile);
2008-11-19 16:58:23 +00:00
VIR_FREE(logfile);
return -1;
}
VIR_FREE(logfile);
if (virSetCloseExec(logfd) < 0) {
virReportSystemError(errno, "%s",
_("Unable to set VM logfile close-on-exec flag"));
VIR_FORCE_CLOSE(logfd);
2008-11-19 16:58:23 +00:00
return -1;
}
/* Do this upfront, so any part of the startup process can add
* runtime state to vm->def that won't be persisted. This let's us
* report implicit runtime defaults in the XML, like vnc listen/socket
*/
VIR_DEBUG("Setting current domain def as transient");
if (virDomainObjSetDefTransient(driver->caps, driver->xmlopt,
vm, true) < 0) {
VIR_FORCE_CLOSE(logfd);
return -1;
}
if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
goto cleanup;
2008-11-19 16:58:23 +00:00
for (i = 0; i < vm->def->nconsoles; i++) {
VIR_FREE(vm->def->consoles[i]->info.alias);
if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0)
goto cleanup;
}
virCommandWriteArgLog(cmd, logfd);
2008-11-19 16:58:23 +00:00
priv->monitor = -1;
2008-11-19 16:58:23 +00:00
virCommandClearCaps(cmd);
virCommandSetOutputFD(cmd, &logfd);
virCommandSetErrorFD(cmd, &logfd);
virCommandDaemonize(cmd);
ret = virCommandRun(cmd, NULL);
if (ret < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
if (autoDestroy &&
(ret = umlProcessAutoDestroyAdd(driver, vm, conn)) < 0)
goto cleanup;
ret = virDomainObjSetDefTransient(driver->caps, driver->xmlopt, vm, false);
cleanup:
VIR_FORCE_CLOSE(logfd);
virCommandFree(cmd);
2008-11-19 16:58:23 +00:00
if (ret < 0) {
virDomainConfVMNWFilterTeardown(vm);
umlCleanupTapDevices(vm);
if (vm->newDef) {
virDomainDefFree(vm->def);
vm->def = vm->newDef;
vm->def->id = -1;
vm->newDef = NULL;
}
}
2008-11-19 16:58:23 +00:00
/* NB we don't mark it running here - we do that async
with inotify */
2009-06-03 11:13:33 +00:00
/* XXX what if someone else tries to start it again
before we get the inotification ? Sounds like
trouble.... */
/* XXX this is bad for events too. must fix this better */
2008-11-19 16:58:23 +00:00
return ret;
}
static void umlShutdownVMDaemon(struct uml_driver *driver,
virDomainObjPtr vm,
virDomainShutoffReason reason)
2008-11-19 16:58:23 +00:00
{
int ret;
umlDomainObjPrivatePtr priv = vm->privateData;
if (!virDomainObjIsActive(vm))
2008-11-19 16:58:23 +00:00
return;
virProcessKill(vm->pid, SIGTERM);
2008-11-19 16:58:23 +00:00
VIR_FORCE_CLOSE(priv->monitor);
2008-11-19 16:58:23 +00:00
if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
VIR_WARN("Got unexpected pid %d != %d",
2008-11-19 16:58:23 +00:00
ret, vm->pid);
}
vm->pid = -1;
vm->def->id = -1;
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
2008-11-19 16:58:23 +00:00
virDomainConfVMNWFilterTeardown(vm);
umlCleanupTapDevices(vm);
/* Stop autodestroy in case guest is restarted */
umlProcessAutoDestroyRemove(driver, vm);
2009-06-03 11:13:33 +00:00
2008-11-19 16:58:23 +00:00
if (vm->newDef) {
virDomainDefFree(vm->def);
vm->def = vm->newDef;
vm->def->id = -1;
vm->newDef = NULL;
}
driver->nactive--;
if (!driver->nactive && driver->inhibitCallback)
driver->inhibitCallback(false, driver->inhibitOpaque);
2008-11-19 16:58:23 +00:00
}
static virDrvOpenStatus umlConnectOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
if (conn->uri == NULL) {
if (uml_driver == NULL)
return VIR_DRV_OPEN_DECLINED;
2008-11-19 16:58:23 +00:00
if (!(conn->uri = virURIParse(uml_driver->privileged ?
"uml:///system" :
"uml:///session")))
return VIR_DRV_OPEN_ERROR;
} else {
if (conn->uri->scheme == NULL ||
STRNEQ(conn->uri->scheme, "uml"))
return VIR_DRV_OPEN_DECLINED;
/* Allow remote driver to deal with URIs with hostname server */
if (conn->uri->server != NULL)
return VIR_DRV_OPEN_DECLINED;
2008-11-19 16:58:23 +00:00
/* Check path and tell them correct path if they made a mistake */
if (uml_driver->privileged) {
if (STRNEQ(conn->uri->path, "/system") &&
STRNEQ(conn->uri->path, "/session")) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected UML URI path '%s', try uml:///system"),
conn->uri->path);
return VIR_DRV_OPEN_ERROR;
}
} else {
if (STRNEQ(conn->uri->path, "/session")) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected UML URI path '%s', try uml:///session"),
conn->uri->path);
return VIR_DRV_OPEN_ERROR;
}
2008-11-19 16:58:23 +00:00
}
/* URI was good, but driver isn't active */
if (uml_driver == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("uml state driver is not active"));
2008-11-19 16:58:23 +00:00
return VIR_DRV_OPEN_ERROR;
}
}
if (virConnectOpenEnsureACL(conn) < 0)
return VIR_DRV_OPEN_ERROR;
2008-11-19 16:58:23 +00:00
conn->privateData = uml_driver;
return VIR_DRV_OPEN_SUCCESS;
}
static int umlConnectClose(virConnectPtr conn)
{
struct uml_driver *driver = conn->privateData;
umlDriverLock(driver);
umlProcessAutoDestroyRun(driver, conn);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
conn->privateData = NULL;
return 0;
}
static const char *umlConnectGetType(virConnectPtr conn) {
if (virConnectGetTypeEnsureACL(conn) < 0)
return NULL;
2008-11-19 16:58:23 +00:00
return "UML";
}
static int umlConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* Trivially secure, since always inside the daemon */
return 1;
}
static int umlConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* Not encrypted, but remote driver takes care of that */
return 0;
}
static int umlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
return 1;
}
static char *umlConnectGetCapabilities(virConnectPtr conn) {
2008-11-19 16:58:23 +00:00
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
char *xml;
if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
return NULL;
umlDriverLock(driver);
xml = virCapabilitiesFormatXML(driver->caps);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
return xml;
}
build: use correct type for pid and similar types No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid constructs like 'int pid'. Our API in libvirt-qemu cannot be changed without breaking ABI; but then again, libvirt-qemu can only be used on systems that support UNIX sockets, which rules out Windows (even if qemu could be compiled there) - so for all points on the call chain that interact with this API decision, we require a different variable name to make it clear that we audited the use for safety. Adding a syntax-check rule only solves half the battle; anywhere that uses printf on a pid_t still needs to be converted, but that will be a separate patch. * cfg.mk (sc_correct_id_types): New syntax check. * src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't use pid_t for pid, and validate for overflow. * include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name for syntax check. * src/vmware/vmware_conf.c (vmwareExtractPid): Likewise. * src/driver.h (virDrvDomainQemuAttach): Likewise. * tools/virsh.c (cmdQemuAttach): Likewise. * src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise. * src/qemu_protocol-structs (qemu_domain_attach_args): Likewise. * src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal): Likewise. * src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise. (qemuParseCommandLinePid): Use pid_t for pid. * daemon/libvirtd.c (daemonForkIntoBackground): Likewise. * src/conf/domain_conf.h (_virDomainObj): Likewise. * src/probes.d (rpc_socket_new): Likewise. * src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise. * src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach): Likewise. * src/qemu/qemu_process.c (qemuProcessAttach): Likewise. * src/qemu/qemu_process.h (qemuProcessAttach): Likewise. * src/uml/uml_driver.c (umlGetProcessInfo): Likewise. * src/util/virnetdev.h (virNetDevSetNamespace): Likewise. * src/util/virnetdev.c (virNetDevSetNamespace): Likewise. * tests/testutils.c (virtTestCaptureProgramOutput): Likewise. * src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t, and gid_t rather than int. * src/security/security_dac.c (virSecurityDACSetOwnership): Likewise. * src/conf/storage_conf.c (virStorageDefParsePerms): Avoid compiler warning.
2012-02-10 23:08:11 +00:00
static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
{
char *proc;
2008-11-19 16:58:23 +00:00
FILE *pidinfo;
unsigned long long usertime, systime;
if (virAsprintf(&proc, "/proc/%lld/stat", (long long) pid) < 0)
2008-11-19 16:58:23 +00:00
return -1;
if (!(pidinfo = fopen(proc, "r"))) {
/* VM probably shut down, so fake 0 */
*cpuTime = 0;
VIR_FREE(proc);
2008-11-19 16:58:23 +00:00
return 0;
}
VIR_FREE(proc);
2008-11-19 16:58:23 +00:00
if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
umlDebug("not enough arg");
VIR_FORCE_FCLOSE(pidinfo);
2008-11-19 16:58:23 +00:00
return -1;
}
/* We got jiffies
* We want nanoseconds
* _SC_CLK_TCK is jiffies per second
* So calculate thus....
2008-11-19 16:58:23 +00:00
*/
*cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
VIR_FORCE_FCLOSE(pidinfo);
2008-11-19 16:58:23 +00:00
return 0;
}
static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
int id)
{
2008-11-19 16:58:23 +00:00
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByID(driver->domains, id);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
cleanup:
if (vm)
virObjectUnlock(vm);
2008-11-19 16:58:23 +00:00
return dom;
}
2008-11-19 16:58:23 +00:00
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
const unsigned char *uuid)
{
2008-11-19 16:58:23 +00:00
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
cleanup:
if (vm)
virObjectUnlock(vm);
2008-11-19 16:58:23 +00:00
return dom;
}
2008-11-19 16:58:23 +00:00
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
const char *name)
{
2008-11-19 16:58:23 +00:00
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByName(driver->domains, name);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
cleanup:
virDomainObjEndAPI(&vm);
2008-11-19 16:58:23 +00:00
return dom;
}
static int umlDomainIsActive(virDomainPtr dom)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr obj;
int ret = -1;
umlDriverLock(driver);
obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
if (!obj) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
goto cleanup;
ret = virDomainObjIsActive(obj);
cleanup:
if (obj)
virObjectUnlock(obj);
return ret;
}
static int umlDomainIsPersistent(virDomainPtr dom)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr obj;
int ret = -1;
umlDriverLock(driver);
obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
if (!obj) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
goto cleanup;
ret = obj->persistent;
cleanup:
if (obj)
virObjectUnlock(obj);
return ret;
}
static int umlDomainIsUpdated(virDomainPtr dom)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr obj;
int ret = -1;
umlDriverLock(driver);
obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
if (!obj) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
goto cleanup;
ret = obj->updated;
cleanup:
if (obj)
virObjectUnlock(obj);
return ret;
}
static int umlConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
struct uml_driver *driver = conn->privateData;
2008-11-19 16:58:23 +00:00
struct utsname ut;
int ret = -1;
2008-11-19 16:58:23 +00:00
if (virConnectGetVersionEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
if (driver->umlVersion == 0) {
uname(&ut);
if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse version %s"), ut.release);
goto cleanup;
}
2008-11-19 16:58:23 +00:00
}
*version = driver->umlVersion;
ret = 0;
cleanup:
umlDriverUnlock(driver);
return ret;
2008-11-19 16:58:23 +00:00
}
static char *umlConnectGetHostname(virConnectPtr conn)
{
if (virConnectGetHostnameEnsureACL(conn) < 0)
return NULL;
return virGetHostname();
}
static int umlConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
struct uml_driver *driver = conn->privateData;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
int n;
2008-11-19 16:58:23 +00:00
if (virConnectListDomainsEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
virConnectListDomainsCheckACL, conn);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
return n;
2008-11-19 16:58:23 +00:00
}
static int umlConnectNumOfDomains(virConnectPtr conn)
{
struct uml_driver *driver = conn->privateData;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
int n;
2008-11-19 16:58:23 +00:00
if (virConnectNumOfDomainsEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
n = virDomainObjListNumOfDomains(driver->domains, true,
virConnectNumOfDomainsCheckACL, conn);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
return n;
}
static virDomainPtr umlDomainCreateXML(virConnectPtr conn, const char *xml,
unsigned int flags)
{
struct uml_driver *driver = conn->privateData;
2008-11-19 16:58:23 +00:00
virDomainDefPtr def;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
virObjectEventPtr event = NULL;
unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
2008-11-19 16:58:23 +00:00
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
VIR_DOMAIN_START_VALIDATE, NULL);
if (flags & VIR_DOMAIN_START_VALIDATE)
parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
Push nwfilter update locking up to top level The NWFilter code has as a deadlock race condition between the virNWFilter{Define,Undefine} APIs and starting of guest VMs due to mis-matched lock ordering. In the virNWFilter{Define,Undefine} codepaths the lock ordering is 1. nwfilter driver lock 2. virt driver lock 3. nwfilter update lock 4. domain object lock In the VM guest startup paths the lock ordering is 1. virt driver lock 2. domain object lock 3. nwfilter update lock As can be seen the domain object and nwfilter update locks are not acquired in a consistent order. The fix used is to push the nwfilter update lock upto the top level resulting in a lock ordering for virNWFilter{Define,Undefine} of 1. nwfilter driver lock 2. nwfilter update lock 3. virt driver lock 4. domain object lock and VM start using 1. nwfilter update lock 2. virt driver lock 3. domain object lock This has the effect of serializing VM startup once again, even if no nwfilters are applied to the guest. There is also the possibility of deadlock due to a call graph loop via virNWFilterInstantiate and virNWFilterInstantiateFilterLate. These two problems mean the lock must be turned into a read/write lock instead of a plain mutex at the same time. The lock is used to serialize changes to the "driver->nwfilters" hash, so the write lock only needs to be held by the define/undefine methods. All other methods can rely on a read lock which allows good concurrency. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-01-22 17:28:29 +00:00
virNWFilterReadLockFilterUpdates();
umlDriverLock(driver);
if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
parse_flags)))
goto cleanup;
2008-11-19 16:58:23 +00:00
if (virDomainCreateXMLEnsureACL(conn, def) < 0)
goto cleanup;
if (!(vm = virDomainObjListAdd(driver->domains, def,
driver->xmlopt,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
def = NULL;
2008-11-19 16:58:23 +00:00
if (umlStartVMDaemon(conn, driver, vm,
(flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
virDomainAuditStart(vm, "booted", false);
virDomainObjListRemove(driver->domains,
vm);
vm = NULL;
goto cleanup;
2008-11-19 16:58:23 +00:00
}
virDomainAuditStart(vm, "booted", true);
event = virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
2008-11-19 16:58:23 +00:00
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
cleanup:
virDomainDefFree(def);
if (vm)
virObjectUnlock(vm);
if (event)
umlDomainEventQueue(driver, event);
umlDriverUnlock(driver);
Push nwfilter update locking up to top level The NWFilter code has as a deadlock race condition between the virNWFilter{Define,Undefine} APIs and starting of guest VMs due to mis-matched lock ordering. In the virNWFilter{Define,Undefine} codepaths the lock ordering is 1. nwfilter driver lock 2. virt driver lock 3. nwfilter update lock 4. domain object lock In the VM guest startup paths the lock ordering is 1. virt driver lock 2. domain object lock 3. nwfilter update lock As can be seen the domain object and nwfilter update locks are not acquired in a consistent order. The fix used is to push the nwfilter update lock upto the top level resulting in a lock ordering for virNWFilter{Define,Undefine} of 1. nwfilter driver lock 2. nwfilter update lock 3. virt driver lock 4. domain object lock and VM start using 1. nwfilter update lock 2. virt driver lock 3. domain object lock This has the effect of serializing VM startup once again, even if no nwfilters are applied to the guest. There is also the possibility of deadlock due to a call graph loop via virNWFilterInstantiate and virNWFilterInstantiateFilterLate. These two problems mean the lock must be turned into a read/write lock instead of a plain mutex at the same time. The lock is used to serialize changes to the "driver->nwfilters" hash, so the write lock only needs to be held by the define/undefine methods. All other methods can rely on a read lock which allows good concurrency. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-01-22 17:28:29 +00:00
virNWFilterUnlockFilterUpdates();
2008-11-19 16:58:23 +00:00
return dom;
}
static int umlDomainShutdownFlags(virDomainPtr dom,
unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
char *info = NULL;
int ret = -1;
2008-11-19 16:58:23 +00:00
virCheckFlags(0, -1);
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching id %d"), dom->id);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
api: require write permission for guest agent interaction I noticed that we allow virDomainGetVcpusFlags even for read-only connections, but that with a flag, it can require guest agent interaction. It is feasible that a malicious guest could intentionally abuse the replies it sends over the guest agent connection to possibly trigger a bug in libvirt's JSON parser, or withhold an answer so as to prevent the use of the agent in a later command such as a shutdown request. Although we don't know of any such exploits now (and therefore don't mind posting this patch publicly without trying to get a CVE assigned), it is better to err on the side of caution and explicitly require full access to any domain where the API requires guest interaction to operate correctly. I audited all commands that are marked as conditionally using a guest agent. Note that at least virDomainFSTrim is documented as needing a guest agent, but that such use is unconditional depending on the hypervisor (so the existing domain:fs_trim ACL should be sufficient there, rather than also requirng domain:write). But when designing future APIs, such as the plans for obtaining a domain's IP addresses, we should copy the approach of this patch in making interaction with the guest be specified via a flag, and use that flag to also require stricter access checks. * src/libvirt.c (virDomainGetVcpusFlags): Forbid guest interaction on read-only connection. (virDomainShutdownFlags, virDomainReboot): Improve docs on agent interaction. * src/remote/remote_protocol.x (REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML) (REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS) (REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS, REMOTE_PROC_DOMAIN_REBOOT) (REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS): Require domain:write for any conditional use of a guest agent. * src/xen/xen_driver.c: Fix clients. * src/libxl/libxl_driver.c: Likewise. * src/uml/uml_driver.c: Likewise. * src/qemu/qemu_driver.c: Likewise. * src/lxc/lxc_driver.c: Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-21 17:37:29 +00:00
if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
#if 0
if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("shutdown operation failed"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
ret = 0;
2008-11-19 16:58:23 +00:00
#endif
cleanup:
VIR_FREE(info);
if (vm)
virObjectUnlock(vm);
return ret;
2008-11-19 16:58:23 +00:00
}
static int
umlDomainShutdown(virDomainPtr dom)
{
return umlDomainShutdownFlags(dom, 0);
}
2008-11-19 16:58:23 +00:00
static int
umlDomainDestroyFlags(virDomainPtr dom,
unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virObjectEventPtr event = NULL;
int ret = -1;
2008-11-19 16:58:23 +00:00
virCheckFlags(0, -1);
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching id %d"), dom->id);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
virDomainAuditStop(vm, "destroyed");
event = virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (!vm->persistent) {
virDomainObjListRemove(driver->domains,
vm);
vm = NULL;
}
ret = 0;
2008-11-19 16:58:23 +00:00
cleanup:
if (vm)
virObjectUnlock(vm);
if (event)
umlDomainEventQueue(driver, event);
umlDriverUnlock(driver);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainDestroy(virDomainPtr dom)
{
return umlDomainDestroyFlags(dom, 0);
}
2008-11-19 16:58:23 +00:00
static char *umlDomainGetOSType(virDomainPtr dom) {
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
char *type = NULL;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
goto cleanup;
cleanup:
if (vm)
virObjectUnlock(vm);
2008-11-19 16:58:23 +00:00
return type;
}
/* Returns max memory in kb, 0 if 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
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
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;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
ret = virDomainDefGetMemoryActual(vm->def);
2008-11-19 16:58:23 +00:00
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
if (newmax < vm->def->mem.cur_balloon) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("cannot set max memory lower than current memory"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
virDomainDefSetMemoryInitial(vm->def, newmax);
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
if (virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("cannot set memory of an active domain"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (newmem > virDomainDefGetMemoryActual(vm->def)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("cannot set memory higher than max memory"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
vm->def->mem.cur_balloon = newmem;
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainGetInfo(virDomainPtr dom,
virDomainInfoPtr info)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
info->state = virDomainObjGetState(vm, NULL);
2008-11-19 16:58:23 +00:00
if (!virDomainObjIsActive(vm)) {
2008-11-19 16:58:23 +00:00
info->cpuTime = 0;
} else {
if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("cannot read cputime for domain"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
}
info->maxMem = virDomainDefGetMemoryActual(vm->def);
info->memory = vm->def->mem.cur_balloon;
2008-11-19 16:58:23 +00:00
info->nrVirtCpu = vm->def->vcpus;
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
2008-11-19 16:58:23 +00:00
}
static int
umlDomainGetState(virDomainPtr dom,
int *state,
int *reason,
unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
virCheckFlags(0, -1);
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
*state = virDomainObjGetState(vm, reason);
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static char *umlDomainGetXMLDesc(virDomainPtr dom,
unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
char *ret = NULL;
/* Flags checked by virDomainDefFormat */
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
goto cleanup;
ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
vm->newDef : vm->def,
virDomainDefFormatConvertXMLFlags(flags));
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlConnectListDefinedDomains(virConnectPtr conn,
char **const names, int nnames) {
struct uml_driver *driver = conn->privateData;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
int n;
2008-11-19 16:58:23 +00:00
if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
virConnectListDefinedDomainsCheckACL, conn);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
return n;
2008-11-19 16:58:23 +00:00
}
static int umlConnectNumOfDefinedDomains(virConnectPtr conn)
{
struct uml_driver *driver = conn->privateData;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
int n;
2008-11-19 16:58:23 +00:00
if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
n = virDomainObjListNumOfDomains(driver->domains, false,
virConnectNumOfDefinedDomainsCheckACL, conn);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
return n;
}
static int umlDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virObjectEventPtr event = NULL;
int ret = -1;
2008-11-19 16:58:23 +00:00
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
Push nwfilter update locking up to top level The NWFilter code has as a deadlock race condition between the virNWFilter{Define,Undefine} APIs and starting of guest VMs due to mis-matched lock ordering. In the virNWFilter{Define,Undefine} codepaths the lock ordering is 1. nwfilter driver lock 2. virt driver lock 3. nwfilter update lock 4. domain object lock In the VM guest startup paths the lock ordering is 1. virt driver lock 2. domain object lock 3. nwfilter update lock As can be seen the domain object and nwfilter update locks are not acquired in a consistent order. The fix used is to push the nwfilter update lock upto the top level resulting in a lock ordering for virNWFilter{Define,Undefine} of 1. nwfilter driver lock 2. nwfilter update lock 3. virt driver lock 4. domain object lock and VM start using 1. nwfilter update lock 2. virt driver lock 3. domain object lock This has the effect of serializing VM startup once again, even if no nwfilters are applied to the guest. There is also the possibility of deadlock due to a call graph loop via virNWFilterInstantiate and virNWFilterInstantiateFilterLate. These two problems mean the lock must be turned into a read/write lock instead of a plain mutex at the same time. The lock is used to serialize changes to the "driver->nwfilters" hash, so the write lock only needs to be held by the define/undefine methods. All other methods can rely on a read lock which allows good concurrency. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-01-22 17:28:29 +00:00
virNWFilterReadLockFilterUpdates();
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
ret = umlStartVMDaemon(dom->conn, driver, vm,
(flags & VIR_DOMAIN_START_AUTODESTROY));
virDomainAuditStart(vm, "booted", ret >= 0);
if (ret == 0)
event = virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
cleanup:
if (vm)
virObjectUnlock(vm);
if (event)
umlDomainEventQueue(driver, event);
umlDriverUnlock(driver);
Push nwfilter update locking up to top level The NWFilter code has as a deadlock race condition between the virNWFilter{Define,Undefine} APIs and starting of guest VMs due to mis-matched lock ordering. In the virNWFilter{Define,Undefine} codepaths the lock ordering is 1. nwfilter driver lock 2. virt driver lock 3. nwfilter update lock 4. domain object lock In the VM guest startup paths the lock ordering is 1. virt driver lock 2. domain object lock 3. nwfilter update lock As can be seen the domain object and nwfilter update locks are not acquired in a consistent order. The fix used is to push the nwfilter update lock upto the top level resulting in a lock ordering for virNWFilter{Define,Undefine} of 1. nwfilter driver lock 2. nwfilter update lock 3. virt driver lock 4. domain object lock and VM start using 1. nwfilter update lock 2. virt driver lock 3. domain object lock This has the effect of serializing VM startup once again, even if no nwfilters are applied to the guest. There is also the possibility of deadlock due to a call graph loop via virNWFilterInstantiate and virNWFilterInstantiateFilterLate. These two problems mean the lock must be turned into a read/write lock instead of a plain mutex at the same time. The lock is used to serialize changes to the "driver->nwfilters" hash, so the write lock only needs to be held by the define/undefine methods. All other methods can rely on a read lock which allows good concurrency. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-01-22 17:28:29 +00:00
virNWFilterUnlockFilterUpdates();
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainCreate(virDomainPtr dom)
{
return umlDomainCreateWithFlags(dom, 0);
}
2008-11-19 16:58:23 +00:00
static virDomainPtr
umlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
{
struct uml_driver *driver = conn->privateData;
2008-11-19 16:58:23 +00:00
virDomainDefPtr def;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
2008-11-19 16:58:23 +00:00
if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
umlDriverLock(driver);
if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
parse_flags)))
goto cleanup;
2008-11-19 16:58:23 +00:00
if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
goto cleanup;
if (!(vm = virDomainObjListAdd(driver->domains, def,
driver->xmlopt,
0, NULL)))
goto cleanup;
def = NULL;
2008-11-19 16:58:23 +00:00
vm->persistent = 1;
if (virDomainSaveConfig(driver->configDir,
2008-11-19 16:58:23 +00:00
vm->newDef ? vm->newDef : vm->def) < 0) {
virDomainObjListRemove(driver->domains,
vm);
vm = NULL;
goto cleanup;
2008-11-19 16:58:23 +00:00
}
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
cleanup:
virDomainDefFree(def);
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
return dom;
}
static virDomainPtr
umlDomainDefineXML(virConnectPtr conn, const char *xml)
{
return umlDomainDefineXMLFlags(conn, xml, 0);
}
static int umlDomainUndefineFlags(virDomainPtr dom,
unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
2008-11-19 16:58:23 +00:00
virCheckFlags(0, -1);
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
if (!vm->persistent) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("cannot undefine transient domain"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
if (virDomainObjIsActive(vm)) {
vm->persistent = 0;
} else {
virDomainObjListRemove(driver->domains, vm);
vm = NULL;
}
ret = 0;
2008-11-19 16:58:23 +00:00
cleanup:
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainUndefine(virDomainPtr dom)
{
return umlDomainUndefineFlags(dom, 0);
}
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
size_t i;
char *cmd = NULL;
char *reply = NULL;
for (i = 0; i < vm->def->ndisks; i++) {
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("target %s already exists"), disk->dst);
return -1;
}
}
if (!virDomainDiskGetSource(disk)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("disk source path is missing"));
goto error;
}
if (virAsprintf(&cmd, "config %s=%s", disk->dst,
virDomainDiskGetSource(disk)) < 0)
return -1;
if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
goto error;
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
goto error;
virDomainDiskInsertPreAlloced(vm->def, disk);
VIR_FREE(reply);
VIR_FREE(cmd);
return 0;
error:
VIR_FREE(reply);
VIR_FREE(cmd);
return -1;
}
static int umlDomainAttachDevice(virDomainPtr dom, const char *xml)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virDomainDeviceDefPtr dev = NULL;
int ret = -1;
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
}
if (virDomainAttachDeviceEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("cannot attach device on inactive domain"));
goto cleanup;
}
dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
VIR_DOMAIN_DEF_PARSE_INACTIVE);
if (dev == NULL)
goto cleanup;
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) {
ret = umlDomainAttachUmlDisk(driver, vm, dev->data.disk);
if (ret == 0)
dev->data.disk = NULL;
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk bus '%s' cannot be hotplugged."),
virDomainDiskBusTypeToString(dev->data.disk->bus));
}
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("device type '%s' cannot be attached"),
virDomainDeviceTypeToString(dev->type));
goto cleanup;
}
cleanup:
virDomainDeviceDefFree(dev);
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
return ret;
}
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
const char *xml,
unsigned int flags)
{
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("cannot modify the persistent configuration of a domain"));
return -1;
}
return umlDomainAttachDevice(dom, xml);
}
static int umlDomainDetachUmlDisk(struct uml_driver *driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
size_t i;
int ret = -1;
virDomainDiskDefPtr detach = NULL;
char *cmd;
char *reply;
for (i = 0; i < vm->def->ndisks; i++) {
if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst))
break;
}
if (i == vm->def->ndisks) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("disk %s not found"), dev->data.disk->dst);
return -1;
}
detach = vm->def->disks[i];
if (virAsprintf(&cmd, "remove %s", detach->dst) < 0)
return -1;
if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
goto cleanup;
virDomainDiskRemove(vm->def, i);
virDomainDiskDefFree(detach);
ret = 0;
VIR_FREE(reply);
cleanup:
VIR_FREE(cmd);
return ret;
}
static int umlDomainDetachDevice(virDomainPtr dom, const char *xml)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virDomainDeviceDefPtr dev = NULL;
int ret = -1;
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
}
if (virDomainDetachDeviceEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("cannot detach device on inactive domain"));
goto cleanup;
}
dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
VIR_DOMAIN_DEF_PARSE_INACTIVE);
if (dev == NULL)
goto cleanup;
if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML)
ret = umlDomainDetachUmlDisk(driver, vm, dev);
maint: use consistent if-else braces in remaining spots I'm about to add a syntax check that enforces our documented HACKING style of always using matching {} on if-else statements. This patch focuses on all remaining problems, where there weren't enough issues to warrant splitting it further. * src/remote/remote_driver.c (doRemoteOpen): Correct use of {}. * src/security/virt-aa-helper.c (vah_add_path, valid_path, main): Likewise. * src/rpc/virnetsocket.c (virNetSocketNewConnectLibSSH2): Likewise. * src/esx/esx_vi_types.c (esxVI_Type_FromString): Likewise. * src/uml/uml_driver.c (umlDomainDetachDevice): Likewise. * src/util/viralloc.c (virShrinkN): Likewise. * src/util/virbuffer.c (virBufferURIEncodeString): Likewise. * src/util/virdbus.c (virDBusCall): Likewise. * src/util/virnetdev.c (virNetDevValidateConfig): Likewise. * src/util/virnetdevvportprofile.c (virNetDevVPortProfileGetNthParent): Likewise. * src/util/virpci.c (virPCIDeviceIterDevices) (virPCIDeviceWaitForCleanup) (virPCIDeviceIsBehindSwitchLackingACS): Likewise. * src/util/virsocketaddr.c (virSocketAddrGetNumNetmaskBits): Likewise. * src/util/viruri.c (virURIParseParams): Likewise. * daemon/stream.c (daemonStreamHandleAbort): Likewise. * tests/testutils.c (virtTestResult): Likewise. * tests/cputest.c (cpuTestBaseline): Likewise. * tools/virsh-domain.c (cmdDomPMSuspend): Likewise. * tools/virsh-host.c (cmdNodeSuspend): Likewise. * src/esx/esx_vi_generator.py (Type.generate_typefromstring): Tweak generated code. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-09-03 19:39:21 +00:00
else
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("This type of disk cannot be hot unplugged"));
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("This type of device cannot be hot unplugged"));
}
cleanup:
virDomainDeviceDefFree(dev);
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
return ret;
}
static int
umlDomainDetachDeviceFlags(virDomainPtr dom,
const char *xml,
unsigned int flags)
{
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("cannot modify the persistent configuration of a domain"));
return -1;
}
return umlDomainDetachDevice(dom, xml);
}
2008-11-19 16:58:23 +00:00
static int umlDomainGetAutostart(virDomainPtr dom,
int *autostart)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
2008-11-19 16:58:23 +00:00
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
*autostart = vm->autostart;
ret = 0;
2008-11-19 16:58:23 +00:00
cleanup:
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
return ret;
2008-11-19 16:58:23 +00:00
}
static int umlDomainSetAutostart(virDomainPtr dom,
int autostart)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
2008-11-19 16:58:23 +00:00
char *configFile = NULL, *autostartLink = NULL;
int ret = -1;
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
if (!vm->persistent) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("cannot set autostart for transient domain"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
autostart = (autostart != 0);
if (vm->autostart != autostart) {
if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
goto cleanup;
if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
goto cleanup;
2008-11-19 16:58:23 +00:00
if (autostart) {
if (virFileMakePath(driver->autostartDir) < 0) {
virReportSystemError(errno,
_("cannot create autostart directory %s"),
driver->autostartDir);
goto cleanup;
}
2008-11-19 16:58:23 +00:00
if (symlink(configFile, autostartLink) < 0) {
virReportSystemError(errno,
_("Failed to create symlink '%s to '%s'"),
autostartLink, configFile);
goto cleanup;
}
} else {
if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
virReportSystemError(errno,
_("Failed to delete symlink '%s'"),
autostartLink);
goto cleanup;
}
2008-11-19 16:58:23 +00:00
}
vm->autostart = autostart;
2008-11-19 16:58:23 +00:00
}
ret = 0;
cleanup:
2008-11-19 16:58:23 +00:00
VIR_FREE(configFile);
VIR_FREE(autostartLink);
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
return ret;
}
static int
umlDomainBlockPeek(virDomainPtr dom,
const char *path,
unsigned long long offset, size_t size,
void *buffer,
unsigned int flags)
2008-11-19 16:58:23 +00:00
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
int fd = -1, ret = -1;
const char *actual;
2008-11-19 16:58:23 +00:00
virCheckFlags(0, -1);
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
2008-11-19 16:58:23 +00:00
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
2008-11-19 16:58:23 +00:00
if (!path || path[0] == '\0') {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("NULL or empty path"));
goto cleanup;
2008-11-19 16:58:23 +00:00
}
/* Check the path belongs to this domain. */
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
if (!(actual = virDomainDiskPathByName(vm->def, path))) {
virReportError(VIR_ERR_INVALID_ARG,
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
_("invalid path '%s'"), path);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
path = actual;
2008-11-19 16:58:23 +00:00
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
/* The path is correct, now try to open it and get its size. */
fd = open(path, O_RDONLY);
if (fd == -1) {
virReportSystemError(errno,
_("cannot open %s"), path);
goto cleanup;
}
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
/* Seek and read. */
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
* be 64 bits on all platforms.
*/
if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
saferead(fd, buffer, size) == (ssize_t) -1) {
virReportSystemError(errno,
_("cannot read %s"), path);
goto cleanup;
2008-11-19 16:58:23 +00:00
}
snapshot: also support disks by path I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
2011-08-20 02:38:36 +00:00
ret = 0;
cleanup:
VIR_FORCE_CLOSE(fd);
if (vm)
virObjectUnlock(vm);
2008-11-19 16:58:23 +00:00
return ret;
}
static int
umlDomainOpenConsole(virDomainPtr dom,
const char *dev_name,
virStreamPtr st,
unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
int ret = -1;
virDomainChrDefPtr chr = NULL;
size_t i;
virCheckFlags(0, -1);
umlDriverLock(driver);
virUUIDFormat(dom->uuid, uuidstr);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
}
if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("domain is not running"));
goto cleanup;
}
if (dev_name) {
for (i = 0; i < vm->def->nconsoles; i++) {
if (vm->def->consoles[i]->info.alias &&
STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
chr = vm->def->consoles[i];
break;
}
}
} else {
if (vm->def->nconsoles)
chr = vm->def->consoles[0];
else if (vm->def->nserials)
chr = vm->def->serials[0];
}
if (!chr) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find console device '%s'"),
dev_name ? dev_name : _("default"));
goto cleanup;
}
domain_conf: split source data out from ChrDef This opens up the possibility of reusing the smaller ChrSourceDef for both qemu monitor and a passthrough smartcard device. * src/conf/domain_conf.h (_virDomainChrDef): Factor host details... (_virDomainChrSourceDef): ...into new struct. (virDomainChrSourceDefFree): New prototype. * src/conf/domain_conf.c (virDomainChrDefFree) (virDomainChrDefParseXML, virDomainChrDefFormat): Split... (virDomainChrSourceDefClear, virDomainChrSourceDefFree) (virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat): ...into new functions. (virDomainChrDefParseTargetXML): Update clients to reflect type split. * src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel) (virVMXFormatSerial, virVMXFormatParallel): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise. * src/xen/xend_internal.c (xenDaemonParseSxprChar) (xenDaemonFormatSxprChr): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial) (vboxAttachParallel): Likewise. * src/security/security_dac.c (virSecurityDACSetChardevLabel) (virSecurityDACSetChardevCallback) (virSecurityDACRestoreChardevLabel) (virSecurityDACRestoreChardevCallback): Likewise. * src/security/security_selinux.c (SELinuxSetSecurityChardevLabel) (SELinuxSetSecurityChardevCallback) (SELinuxRestoreSecurityChardevLabel) (SELinuxSetSecurityChardevCallback): Likewise. * src/security/virt-aa-helper.c (get_files): Likewise. * src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole): Likewise. * src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise. * src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY) (umlDomainOpenConsole): Likewise. * src/qemu/qemu_command.c (qemuBuildChrChardevStr) (qemuBuildChrArgStr, qemuBuildCommandLine) (qemuParseCommandLineChr): Likewise. * src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat) (qemuDomainObjPrivateXMLParse): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor) (qemudFindCharDevicePTYs, qemuPrepareChardevDevice) (qemuPrepareMonitorChr, qemudShutdownVMDaemon) (qemuDomainOpenConsole): Likewise. * src/qemu/qemu_command.h (qemuBuildChrChardevStr) (qemuBuildChrArgStr): Delete, now that they are static. * src/libvirt_private.syms (domain_conf.h): New exports. * cfg.mk (useless_free_options): Update list. * tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update tests.
2011-01-07 22:45:01 +00:00
if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("character device %s is not using a PTY"),
dev_name ? dev_name : NULLSTR(chr->info.alias));
goto cleanup;
}
if (virFDStreamOpenFile(st, chr->source.data.file.path,
0, 0, O_RDWR) < 0)
goto cleanup;
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
umlDriverUnlock(driver);
return ret;
}
2008-11-19 16:58:23 +00:00
static int
umlConnectDomainEventRegister(virConnectPtr conn,
virConnectDomainEventCallback callback,
void *opaque,
virFreeCallback freecb)
{
struct uml_driver *driver = conn->privateData;
event: make deregister return value match docs Ever since their introduction (commit 1509b80 in v0.5.0 for virConnectDomainEventRegister, commit 4445723 in v0.8.0 for virConnectDomainEventDeregisterAny), the event deregistration functions have been documented as returning 0 on success; likewise for older registration (only the newer RegisterAny must return a non-zero callbackID). And now that we are adding virConnectNetworkEventDeregisterAny for v1.2.1, it should have the same semantics. Fortunately, all of the stateful drivers have been obeying the docs and returning 0, thanks to the way the remote_driver tracks things (in fact, the RPC wire protocol is unable to send a return value for DomainEventRegisterAny, at least not without adding a new RPC number). Well, except for vbox, which was always failing deregistration, due to failure to set the return value to anything besides its initial -1. But for local drivers, such as test:///default, we've been returning non-zero numbers; worse, the non-zero numbers have differed over time. For example, in Fedora 12 (libvirt 0.8.2), calling Register twice would return 0 and 1 [the callbackID generated under the hood]; while in Fedora 20 (libvirt 1.1.3), it returns 1 and 2 [the number of callbacks registered for that event type]. Since we have changed the behavior over time, and since it differs by local vs. remote, we can safely argue that no one could have been reasonably relying on any particular behavior, so we might as well obey the docs, as well as prepare callers that might deal with older clients to not be surprised if the docs are not strictly followed. For consistency, this patch fixes the code for all drivers, even though it only makes an impact for vbox and for local drivers. By fixing all drivers, future copy and paste from a remote driver to a local driver is less likely to reintroduce the bug. Finally, update the testsuite to gain some coverage of the issue for local drivers, including the first test of old-style domain event registration via function pointer instead of event id. * src/libvirt.c (virConnectDomainEventRegister) (virConnectDomainEventDeregister) (virConnectDomainEventDeregisterAny): Clarify docs. * src/libxl/libxl_driver.c (libxlConnectDomainEventRegister) (libxlConnectDomainEventDeregister) (libxlConnectDomainEventDeregisterAny): Match documentation. * src/lxc/lxc_driver.c (lxcConnectDomainEventRegister) (lxcConnectDomainEventDeregister) (lxcConnectDomainEventDeregisterAny): Likewise. * src/test/test_driver.c (testConnectDomainEventRegister) (testConnectDomainEventDeregister) (testConnectDomainEventDeregisterAny) (testConnectNetworkEventDeregisterAny): Likewise. * src/uml/uml_driver.c (umlConnectDomainEventRegister) (umlConnectDomainEventDeregister) (umlConnectDomainEventDeregisterAny): Likewise. * src/vbox/vbox_tmpl.c (vboxConnectDomainEventRegister) (vboxConnectDomainEventDeregister) (vboxConnectDomainEventDeregisterAny): Likewise. * src/xen/xen_driver.c (xenUnifiedConnectDomainEventRegister) (xenUnifiedConnectDomainEventDeregister) (xenUnifiedConnectDomainEventDeregisterAny): Likewise. * src/network/bridge_driver.c (networkConnectNetworkEventDeregisterAny): Likewise. * tests/objecteventtest.c (testDomainCreateXMLOld): New test. (mymain): Run it. (testDomainCreateXML): Check return values. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-03 21:21:17 +00:00
int ret = 0;
if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
event: make deregister return value match docs Ever since their introduction (commit 1509b80 in v0.5.0 for virConnectDomainEventRegister, commit 4445723 in v0.8.0 for virConnectDomainEventDeregisterAny), the event deregistration functions have been documented as returning 0 on success; likewise for older registration (only the newer RegisterAny must return a non-zero callbackID). And now that we are adding virConnectNetworkEventDeregisterAny for v1.2.1, it should have the same semantics. Fortunately, all of the stateful drivers have been obeying the docs and returning 0, thanks to the way the remote_driver tracks things (in fact, the RPC wire protocol is unable to send a return value for DomainEventRegisterAny, at least not without adding a new RPC number). Well, except for vbox, which was always failing deregistration, due to failure to set the return value to anything besides its initial -1. But for local drivers, such as test:///default, we've been returning non-zero numbers; worse, the non-zero numbers have differed over time. For example, in Fedora 12 (libvirt 0.8.2), calling Register twice would return 0 and 1 [the callbackID generated under the hood]; while in Fedora 20 (libvirt 1.1.3), it returns 1 and 2 [the number of callbacks registered for that event type]. Since we have changed the behavior over time, and since it differs by local vs. remote, we can safely argue that no one could have been reasonably relying on any particular behavior, so we might as well obey the docs, as well as prepare callers that might deal with older clients to not be surprised if the docs are not strictly followed. For consistency, this patch fixes the code for all drivers, even though it only makes an impact for vbox and for local drivers. By fixing all drivers, future copy and paste from a remote driver to a local driver is less likely to reintroduce the bug. Finally, update the testsuite to gain some coverage of the issue for local drivers, including the first test of old-style domain event registration via function pointer instead of event id. * src/libvirt.c (virConnectDomainEventRegister) (virConnectDomainEventDeregister) (virConnectDomainEventDeregisterAny): Clarify docs. * src/libxl/libxl_driver.c (libxlConnectDomainEventRegister) (libxlConnectDomainEventDeregister) (libxlConnectDomainEventDeregisterAny): Match documentation. * src/lxc/lxc_driver.c (lxcConnectDomainEventRegister) (lxcConnectDomainEventDeregister) (lxcConnectDomainEventDeregisterAny): Likewise. * src/test/test_driver.c (testConnectDomainEventRegister) (testConnectDomainEventDeregister) (testConnectDomainEventDeregisterAny) (testConnectNetworkEventDeregisterAny): Likewise. * src/uml/uml_driver.c (umlConnectDomainEventRegister) (umlConnectDomainEventDeregister) (umlConnectDomainEventDeregisterAny): Likewise. * src/vbox/vbox_tmpl.c (vboxConnectDomainEventRegister) (vboxConnectDomainEventDeregister) (vboxConnectDomainEventDeregisterAny): Likewise. * src/xen/xen_driver.c (xenUnifiedConnectDomainEventRegister) (xenUnifiedConnectDomainEventDeregister) (xenUnifiedConnectDomainEventDeregisterAny): Likewise. * src/network/bridge_driver.c (networkConnectNetworkEventDeregisterAny): Likewise. * tests/objecteventtest.c (testDomainCreateXMLOld): New test. (mymain): Run it. (testDomainCreateXML): Check return values. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-03 21:21:17 +00:00
if (virDomainEventStateRegister(conn,
driver->domainEventState,
callback, opaque, freecb) < 0)
ret = -1;
umlDriverUnlock(driver);
return ret;
}
static int
umlConnectDomainEventDeregister(virConnectPtr conn,
virConnectDomainEventCallback callback)
{
struct uml_driver *driver = conn->privateData;
event: make deregister return value match docs Ever since their introduction (commit 1509b80 in v0.5.0 for virConnectDomainEventRegister, commit 4445723 in v0.8.0 for virConnectDomainEventDeregisterAny), the event deregistration functions have been documented as returning 0 on success; likewise for older registration (only the newer RegisterAny must return a non-zero callbackID). And now that we are adding virConnectNetworkEventDeregisterAny for v1.2.1, it should have the same semantics. Fortunately, all of the stateful drivers have been obeying the docs and returning 0, thanks to the way the remote_driver tracks things (in fact, the RPC wire protocol is unable to send a return value for DomainEventRegisterAny, at least not without adding a new RPC number). Well, except for vbox, which was always failing deregistration, due to failure to set the return value to anything besides its initial -1. But for local drivers, such as test:///default, we've been returning non-zero numbers; worse, the non-zero numbers have differed over time. For example, in Fedora 12 (libvirt 0.8.2), calling Register twice would return 0 and 1 [the callbackID generated under the hood]; while in Fedora 20 (libvirt 1.1.3), it returns 1 and 2 [the number of callbacks registered for that event type]. Since we have changed the behavior over time, and since it differs by local vs. remote, we can safely argue that no one could have been reasonably relying on any particular behavior, so we might as well obey the docs, as well as prepare callers that might deal with older clients to not be surprised if the docs are not strictly followed. For consistency, this patch fixes the code for all drivers, even though it only makes an impact for vbox and for local drivers. By fixing all drivers, future copy and paste from a remote driver to a local driver is less likely to reintroduce the bug. Finally, update the testsuite to gain some coverage of the issue for local drivers, including the first test of old-style domain event registration via function pointer instead of event id. * src/libvirt.c (virConnectDomainEventRegister) (virConnectDomainEventDeregister) (virConnectDomainEventDeregisterAny): Clarify docs. * src/libxl/libxl_driver.c (libxlConnectDomainEventRegister) (libxlConnectDomainEventDeregister) (libxlConnectDomainEventDeregisterAny): Match documentation. * src/lxc/lxc_driver.c (lxcConnectDomainEventRegister) (lxcConnectDomainEventDeregister) (lxcConnectDomainEventDeregisterAny): Likewise. * src/test/test_driver.c (testConnectDomainEventRegister) (testConnectDomainEventDeregister) (testConnectDomainEventDeregisterAny) (testConnectNetworkEventDeregisterAny): Likewise. * src/uml/uml_driver.c (umlConnectDomainEventRegister) (umlConnectDomainEventDeregister) (umlConnectDomainEventDeregisterAny): Likewise. * src/vbox/vbox_tmpl.c (vboxConnectDomainEventRegister) (vboxConnectDomainEventDeregister) (vboxConnectDomainEventDeregisterAny): Likewise. * src/xen/xen_driver.c (xenUnifiedConnectDomainEventRegister) (xenUnifiedConnectDomainEventDeregister) (xenUnifiedConnectDomainEventDeregisterAny): Likewise. * src/network/bridge_driver.c (networkConnectNetworkEventDeregisterAny): Likewise. * tests/objecteventtest.c (testDomainCreateXMLOld): New test. (mymain): Run it. (testDomainCreateXML): Check return values. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-03 21:21:17 +00:00
int ret = 0;
if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
event: make deregister return value match docs Ever since their introduction (commit 1509b80 in v0.5.0 for virConnectDomainEventRegister, commit 4445723 in v0.8.0 for virConnectDomainEventDeregisterAny), the event deregistration functions have been documented as returning 0 on success; likewise for older registration (only the newer RegisterAny must return a non-zero callbackID). And now that we are adding virConnectNetworkEventDeregisterAny for v1.2.1, it should have the same semantics. Fortunately, all of the stateful drivers have been obeying the docs and returning 0, thanks to the way the remote_driver tracks things (in fact, the RPC wire protocol is unable to send a return value for DomainEventRegisterAny, at least not without adding a new RPC number). Well, except for vbox, which was always failing deregistration, due to failure to set the return value to anything besides its initial -1. But for local drivers, such as test:///default, we've been returning non-zero numbers; worse, the non-zero numbers have differed over time. For example, in Fedora 12 (libvirt 0.8.2), calling Register twice would return 0 and 1 [the callbackID generated under the hood]; while in Fedora 20 (libvirt 1.1.3), it returns 1 and 2 [the number of callbacks registered for that event type]. Since we have changed the behavior over time, and since it differs by local vs. remote, we can safely argue that no one could have been reasonably relying on any particular behavior, so we might as well obey the docs, as well as prepare callers that might deal with older clients to not be surprised if the docs are not strictly followed. For consistency, this patch fixes the code for all drivers, even though it only makes an impact for vbox and for local drivers. By fixing all drivers, future copy and paste from a remote driver to a local driver is less likely to reintroduce the bug. Finally, update the testsuite to gain some coverage of the issue for local drivers, including the first test of old-style domain event registration via function pointer instead of event id. * src/libvirt.c (virConnectDomainEventRegister) (virConnectDomainEventDeregister) (virConnectDomainEventDeregisterAny): Clarify docs. * src/libxl/libxl_driver.c (libxlConnectDomainEventRegister) (libxlConnectDomainEventDeregister) (libxlConnectDomainEventDeregisterAny): Match documentation. * src/lxc/lxc_driver.c (lxcConnectDomainEventRegister) (lxcConnectDomainEventDeregister) (lxcConnectDomainEventDeregisterAny): Likewise. * src/test/test_driver.c (testConnectDomainEventRegister) (testConnectDomainEventDeregister) (testConnectDomainEventDeregisterAny) (testConnectNetworkEventDeregisterAny): Likewise. * src/uml/uml_driver.c (umlConnectDomainEventRegister) (umlConnectDomainEventDeregister) (umlConnectDomainEventDeregisterAny): Likewise. * src/vbox/vbox_tmpl.c (vboxConnectDomainEventRegister) (vboxConnectDomainEventDeregister) (vboxConnectDomainEventDeregisterAny): Likewise. * src/xen/xen_driver.c (xenUnifiedConnectDomainEventRegister) (xenUnifiedConnectDomainEventDeregister) (xenUnifiedConnectDomainEventDeregisterAny): Likewise. * src/network/bridge_driver.c (networkConnectNetworkEventDeregisterAny): Likewise. * tests/objecteventtest.c (testDomainCreateXMLOld): New test. (mymain): Run it. (testDomainCreateXML): Check return values. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-03 21:21:17 +00:00
if (virDomainEventStateDeregister(conn,
driver->domainEventState,
callback) < 0)
ret = -1;
umlDriverUnlock(driver);
return ret;
}
static int
umlConnectDomainEventRegisterAny(virConnectPtr conn,
virDomainPtr dom,
int eventID,
virConnectDomainEventGenericCallback callback,
void *opaque,
virFreeCallback freecb)
{
struct uml_driver *driver = conn->privateData;
int ret;
if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
if (virDomainEventStateRegisterID(conn,
driver->domainEventState,
dom, eventID,
callback, opaque, freecb, &ret) < 0)
ret = -1;
umlDriverUnlock(driver);
return ret;
}
static int
umlConnectDomainEventDeregisterAny(virConnectPtr conn,
int callbackID)
{
struct uml_driver *driver = conn->privateData;
event: make deregister return value match docs Ever since their introduction (commit 1509b80 in v0.5.0 for virConnectDomainEventRegister, commit 4445723 in v0.8.0 for virConnectDomainEventDeregisterAny), the event deregistration functions have been documented as returning 0 on success; likewise for older registration (only the newer RegisterAny must return a non-zero callbackID). And now that we are adding virConnectNetworkEventDeregisterAny for v1.2.1, it should have the same semantics. Fortunately, all of the stateful drivers have been obeying the docs and returning 0, thanks to the way the remote_driver tracks things (in fact, the RPC wire protocol is unable to send a return value for DomainEventRegisterAny, at least not without adding a new RPC number). Well, except for vbox, which was always failing deregistration, due to failure to set the return value to anything besides its initial -1. But for local drivers, such as test:///default, we've been returning non-zero numbers; worse, the non-zero numbers have differed over time. For example, in Fedora 12 (libvirt 0.8.2), calling Register twice would return 0 and 1 [the callbackID generated under the hood]; while in Fedora 20 (libvirt 1.1.3), it returns 1 and 2 [the number of callbacks registered for that event type]. Since we have changed the behavior over time, and since it differs by local vs. remote, we can safely argue that no one could have been reasonably relying on any particular behavior, so we might as well obey the docs, as well as prepare callers that might deal with older clients to not be surprised if the docs are not strictly followed. For consistency, this patch fixes the code for all drivers, even though it only makes an impact for vbox and for local drivers. By fixing all drivers, future copy and paste from a remote driver to a local driver is less likely to reintroduce the bug. Finally, update the testsuite to gain some coverage of the issue for local drivers, including the first test of old-style domain event registration via function pointer instead of event id. * src/libvirt.c (virConnectDomainEventRegister) (virConnectDomainEventDeregister) (virConnectDomainEventDeregisterAny): Clarify docs. * src/libxl/libxl_driver.c (libxlConnectDomainEventRegister) (libxlConnectDomainEventDeregister) (libxlConnectDomainEventDeregisterAny): Match documentation. * src/lxc/lxc_driver.c (lxcConnectDomainEventRegister) (lxcConnectDomainEventDeregister) (lxcConnectDomainEventDeregisterAny): Likewise. * src/test/test_driver.c (testConnectDomainEventRegister) (testConnectDomainEventDeregister) (testConnectDomainEventDeregisterAny) (testConnectNetworkEventDeregisterAny): Likewise. * src/uml/uml_driver.c (umlConnectDomainEventRegister) (umlConnectDomainEventDeregister) (umlConnectDomainEventDeregisterAny): Likewise. * src/vbox/vbox_tmpl.c (vboxConnectDomainEventRegister) (vboxConnectDomainEventDeregister) (vboxConnectDomainEventDeregisterAny): Likewise. * src/xen/xen_driver.c (xenUnifiedConnectDomainEventRegister) (xenUnifiedConnectDomainEventDeregister) (xenUnifiedConnectDomainEventDeregisterAny): Likewise. * src/network/bridge_driver.c (networkConnectNetworkEventDeregisterAny): Likewise. * tests/objecteventtest.c (testDomainCreateXMLOld): New test. (mymain): Run it. (testDomainCreateXML): Check return values. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-03 21:21:17 +00:00
int ret = 0;
if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
event: make deregister return value match docs Ever since their introduction (commit 1509b80 in v0.5.0 for virConnectDomainEventRegister, commit 4445723 in v0.8.0 for virConnectDomainEventDeregisterAny), the event deregistration functions have been documented as returning 0 on success; likewise for older registration (only the newer RegisterAny must return a non-zero callbackID). And now that we are adding virConnectNetworkEventDeregisterAny for v1.2.1, it should have the same semantics. Fortunately, all of the stateful drivers have been obeying the docs and returning 0, thanks to the way the remote_driver tracks things (in fact, the RPC wire protocol is unable to send a return value for DomainEventRegisterAny, at least not without adding a new RPC number). Well, except for vbox, which was always failing deregistration, due to failure to set the return value to anything besides its initial -1. But for local drivers, such as test:///default, we've been returning non-zero numbers; worse, the non-zero numbers have differed over time. For example, in Fedora 12 (libvirt 0.8.2), calling Register twice would return 0 and 1 [the callbackID generated under the hood]; while in Fedora 20 (libvirt 1.1.3), it returns 1 and 2 [the number of callbacks registered for that event type]. Since we have changed the behavior over time, and since it differs by local vs. remote, we can safely argue that no one could have been reasonably relying on any particular behavior, so we might as well obey the docs, as well as prepare callers that might deal with older clients to not be surprised if the docs are not strictly followed. For consistency, this patch fixes the code for all drivers, even though it only makes an impact for vbox and for local drivers. By fixing all drivers, future copy and paste from a remote driver to a local driver is less likely to reintroduce the bug. Finally, update the testsuite to gain some coverage of the issue for local drivers, including the first test of old-style domain event registration via function pointer instead of event id. * src/libvirt.c (virConnectDomainEventRegister) (virConnectDomainEventDeregister) (virConnectDomainEventDeregisterAny): Clarify docs. * src/libxl/libxl_driver.c (libxlConnectDomainEventRegister) (libxlConnectDomainEventDeregister) (libxlConnectDomainEventDeregisterAny): Match documentation. * src/lxc/lxc_driver.c (lxcConnectDomainEventRegister) (lxcConnectDomainEventDeregister) (lxcConnectDomainEventDeregisterAny): Likewise. * src/test/test_driver.c (testConnectDomainEventRegister) (testConnectDomainEventDeregister) (testConnectDomainEventDeregisterAny) (testConnectNetworkEventDeregisterAny): Likewise. * src/uml/uml_driver.c (umlConnectDomainEventRegister) (umlConnectDomainEventDeregister) (umlConnectDomainEventDeregisterAny): Likewise. * src/vbox/vbox_tmpl.c (vboxConnectDomainEventRegister) (vboxConnectDomainEventDeregister) (vboxConnectDomainEventDeregisterAny): Likewise. * src/xen/xen_driver.c (xenUnifiedConnectDomainEventRegister) (xenUnifiedConnectDomainEventDeregister) (xenUnifiedConnectDomainEventDeregisterAny): Likewise. * src/network/bridge_driver.c (networkConnectNetworkEventDeregisterAny): Likewise. * tests/objecteventtest.c (testDomainCreateXMLOld): New test. (mymain): Run it. (testDomainCreateXML): Check return values. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-01-03 21:21:17 +00:00
if (virObjectEventStateDeregisterID(conn,
driver->domainEventState,
callbackID) < 0)
ret = -1;
umlDriverUnlock(driver);
return ret;
}
/* driver must be locked before calling */
static void umlDomainEventQueue(struct uml_driver *driver,
virObjectEventPtr event)
{
virObjectEventStateQueue(driver->domainEventState, event);
}
static int umlConnectListAllDomains(virConnectPtr conn,
virDomainPtr **domains,
unsigned int flags)
{
struct uml_driver *driver = conn->privateData;
int ret = -1;
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
if (virConnectListAllDomainsEnsureACL(conn) < 0)
return -1;
umlDriverLock(driver);
ret = virDomainObjListExport(driver->domains, conn, domains,
virConnectListAllDomainsCheckACL, flags);
umlDriverUnlock(driver);
return ret;
}
static int
umlNodeGetInfo(virConnectPtr conn,
virNodeInfoPtr nodeinfo)
{
if (virNodeGetInfoEnsureACL(conn) < 0)
return -1;
return nodeGetInfo(NULL, nodeinfo);
}
static int
umlNodeGetCPUStats(virConnectPtr conn,
int cpuNum,
virNodeCPUStatsPtr params,
int *nparams,
unsigned int flags)
{
if (virNodeGetCPUStatsEnsureACL(conn) < 0)
return -1;
return nodeGetCPUStats(cpuNum, params, nparams, flags);
}
static int
umlNodeGetMemoryStats(virConnectPtr conn,
int cellNum,
virNodeMemoryStatsPtr params,
int *nparams,
unsigned int flags)
{
if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
return -1;
return nodeGetMemoryStats(NULL, cellNum, params, nparams, flags);
}
static int
umlNodeGetCellsFreeMemory(virConnectPtr conn,
unsigned long long *freeMems,
int startCell,
int maxCells)
{
if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
return -1;
return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}
static unsigned long long
umlNodeGetFreeMemory(virConnectPtr conn)
{
unsigned long long freeMem;
if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
return 0;
if (nodeGetMemory(NULL, &freeMem) < 0)
return 0;
return freeMem;
}
static int
umlNodeGetMemoryParameters(virConnectPtr conn,
virTypedParameterPtr params,
int *nparams,
unsigned int flags)
{
if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
return -1;
return nodeGetMemoryParameters(params, nparams, flags);
}
static int
umlNodeSetMemoryParameters(virConnectPtr conn,
virTypedParameterPtr params,
int nparams,
unsigned int flags)
{
if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
return -1;
return nodeSetMemoryParameters(params, nparams, flags);
}
static int
umlNodeGetCPUMap(virConnectPtr conn,
unsigned char **cpumap,
unsigned int *online,
unsigned int flags)
{
if (virNodeGetCPUMapEnsureACL(conn) < 0)
return -1;
return nodeGetCPUMap(NULL, cpumap, online, flags);
}
static int
umlNodeSuspendForDuration(virConnectPtr conn,
unsigned int target,
unsigned long long duration,
unsigned int flags)
{
if (virNodeSuspendForDurationEnsureACL(conn) < 0)
return -1;
return nodeSuspendForDuration(target, duration, flags);
}
static int
umlNodeGetFreePages(virConnectPtr conn,
unsigned int npages,
unsigned int *pages,
int startCell,
unsigned int cellCount,
unsigned long long *counts,
unsigned int flags)
{
virCheckFlags(0, -1);
if (virNodeGetFreePagesEnsureACL(conn) < 0)
return -1;
return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
}
static int
umlNodeAllocPages(virConnectPtr conn,
unsigned int npages,
unsigned int *pageSizes,
unsigned long long *pageCounts,
int startCell,
unsigned int cellCount,
unsigned int flags)
{
bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);
virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);
if (virNodeAllocPagesEnsureACL(conn) < 0)
return -1;
return nodeAllocPages(npages, pageSizes, pageCounts,
startCell, cellCount, add);
}
static int
umlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
struct uml_driver *driver = dom->conn->privateData;
int ret = -1;
virDomainObjPtr vm;
virCheckFlags(0, -1);
umlDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
umlDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static virHypervisorDriver umlHypervisorDriver = {
.name = "UML",
.connectOpen = umlConnectOpen, /* 0.5.0 */
.connectClose = umlConnectClose, /* 0.5.0 */
.connectGetType = umlConnectGetType, /* 0.5.0 */
.connectGetVersion = umlConnectGetVersion, /* 0.5.0 */
.connectGetHostname = umlConnectGetHostname, /* 0.5.0 */
.nodeGetInfo = umlNodeGetInfo, /* 0.5.0 */
.connectGetCapabilities = umlConnectGetCapabilities, /* 0.5.0 */
.connectListDomains = umlConnectListDomains, /* 0.5.0 */
.connectNumOfDomains = umlConnectNumOfDomains, /* 0.5.0 */
.connectListAllDomains = umlConnectListAllDomains, /* 0.9.13 */
.domainCreateXML = umlDomainCreateXML, /* 0.5.0 */
.domainLookupByID = umlDomainLookupByID, /* 0.5.0 */
.domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
.domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
.domainShutdown = umlDomainShutdown, /* 0.5.0 */
.domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
.domainDestroy = umlDomainDestroy, /* 0.5.0 */
.domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
.domainGetOSType = umlDomainGetOSType, /* 0.5.0 */
.domainGetMaxMemory = umlDomainGetMaxMemory, /* 0.5.0 */
.domainSetMaxMemory = umlDomainSetMaxMemory, /* 0.5.0 */
.domainSetMemory = umlDomainSetMemory, /* 0.5.0 */
.domainGetInfo = umlDomainGetInfo, /* 0.5.0 */
.domainGetState = umlDomainGetState, /* 0.9.2 */
.domainGetXMLDesc = umlDomainGetXMLDesc, /* 0.5.0 */
.connectListDefinedDomains = umlConnectListDefinedDomains, /* 0.5.0 */
.connectNumOfDefinedDomains = umlConnectNumOfDefinedDomains, /* 0.5.0 */
.domainCreate = umlDomainCreate, /* 0.5.0 */
.domainCreateWithFlags = umlDomainCreateWithFlags, /* 0.8.2 */
.domainDefineXML = umlDomainDefineXML, /* 0.5.0 */
.domainDefineXMLFlags = umlDomainDefineXMLFlags, /* 1.2.12 */
.domainUndefine = umlDomainUndefine, /* 0.5.0 */
.domainUndefineFlags = umlDomainUndefineFlags, /* 0.9.4 */
.domainAttachDevice = umlDomainAttachDevice, /* 0.8.4 */
.domainAttachDeviceFlags = umlDomainAttachDeviceFlags, /* 0.8.4 */
.domainDetachDevice = umlDomainDetachDevice, /* 0.8.4 */
.domainDetachDeviceFlags = umlDomainDetachDeviceFlags, /* 0.8.4 */
.domainGetAutostart = umlDomainGetAutostart, /* 0.5.0 */
.domainSetAutostart = umlDomainSetAutostart, /* 0.5.0 */
.domainBlockPeek = umlDomainBlockPeek, /* 0.5.0 */
.nodeGetCPUStats = umlNodeGetCPUStats, /* 0.9.3 */
.nodeGetMemoryStats = umlNodeGetMemoryStats, /* 0.9.3 */
.nodeGetCellsFreeMemory = umlNodeGetCellsFreeMemory, /* 0.5.0 */
.nodeGetFreeMemory = umlNodeGetFreeMemory, /* 0.5.0 */
.nodeGetCPUMap = umlNodeGetCPUMap, /* 1.0.0 */
.connectDomainEventRegister = umlConnectDomainEventRegister, /* 0.9.4 */
.connectDomainEventDeregister = umlConnectDomainEventDeregister, /* 0.9.4 */
.connectIsEncrypted = umlConnectIsEncrypted, /* 0.7.3 */
.connectIsSecure = umlConnectIsSecure, /* 0.7.3 */
.domainIsActive = umlDomainIsActive, /* 0.7.3 */
.domainIsPersistent = umlDomainIsPersistent, /* 0.7.3 */
.domainIsUpdated = umlDomainIsUpdated, /* 0.8.6 */
.connectDomainEventRegisterAny = umlConnectDomainEventRegisterAny, /* 0.9.4 */
.connectDomainEventDeregisterAny = umlConnectDomainEventDeregisterAny, /* 0.9.4 */
.domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */
.connectIsAlive = umlConnectIsAlive, /* 0.9.8 */
.nodeSuspendForDuration = umlNodeSuspendForDuration, /* 0.9.8 */
.nodeGetMemoryParameters = umlNodeGetMemoryParameters, /* 0.10.2 */
.nodeSetMemoryParameters = umlNodeSetMemoryParameters, /* 0.10.2 */
.nodeGetFreePages = umlNodeGetFreePages, /* 1.2.6 */
.nodeAllocPages = umlNodeAllocPages, /* 1.2.9 */
.domainHasManagedSaveImage = umlDomainHasManagedSaveImage, /* 1.2.13 */
2008-11-19 16:58:23 +00:00
};
static virConnectDriver umlConnectDriver = {
.hypervisorDriver = &umlHypervisorDriver,
};
2008-11-19 16:58:23 +00:00
static virStateDriver umlStateDriver = {
.name = "UML",
.stateInitialize = umlStateInitialize,
.stateAutoStart = umlStateAutoStart,
.stateCleanup = umlStateCleanup,
.stateReload = umlStateReload,
2008-11-19 16:58:23 +00:00
};
int umlRegister(void)
{
if (virRegisterConnectDriver(&umlConnectDriver,
true) < 0)
return -1;
if (virRegisterStateDriver(&umlStateDriver) < 0)
return -1;
2008-11-19 16:58:23 +00:00
return 0;
}