2008-03-21 15:03:37 +00:00
|
|
|
/*
|
2015-01-15 14:02:44 +00:00
|
|
|
* Copyright (C) 2010-2015 Red Hat, Inc.
|
2008-03-21 15:03:37 +00:00
|
|
|
* Copyright IBM Corp. 2008
|
|
|
|
*
|
|
|
|
* lxc_driver.c: linux container driver functions
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* David L. Leskovec <dlesko at linux.vnet.ibm.com>
|
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-03-21 15:03:37 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
#include <fcntl.h>
|
2008-03-21 15:03:37 +00:00
|
|
|
#include <sched.h>
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
2008-08-13 10:52:15 +00:00
|
|
|
#include <sys/socket.h>
|
2012-11-22 16:16:06 +00:00
|
|
|
#include <sys/stat.h>
|
2008-08-13 10:52:15 +00:00
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/poll.h>
|
2008-03-21 15:03:37 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <wait.h>
|
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2008-11-04 23:22:06 +00:00
|
|
|
#include "datatypes.h"
|
2012-11-27 16:19:43 +00:00
|
|
|
#include "lxc_cgroup.h"
|
2008-03-21 15:03:37 +00:00
|
|
|
#include "lxc_conf.h"
|
2008-04-10 07:30:52 +00:00
|
|
|
#include "lxc_container.h"
|
2012-07-13 10:16:23 +00:00
|
|
|
#include "lxc_domain.h"
|
2008-03-21 15:03:37 +00:00
|
|
|
#include "lxc_driver.h"
|
2014-02-05 14:10:00 +00:00
|
|
|
#include "lxc_native.h"
|
2012-07-13 11:39:29 +00:00
|
|
|
#include "lxc_process.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#include "virnetdevbridge.h"
|
2011-11-02 16:03:09 +00:00
|
|
|
#include "virnetdevveth.h"
|
2015-03-17 17:46:44 +00:00
|
|
|
#include "virnetdevopenvswitch.h"
|
2009-06-03 13:29:23 +00:00
|
|
|
#include "nodeinfo.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2014-07-05 15:34:39 +00:00
|
|
|
#include "virstats.h"
|
2012-12-12 17:00:34 +00:00
|
|
|
#include "virhook.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2011-08-05 13:13:12 +00:00
|
|
|
#include "virpidfile.h"
|
2010-10-22 13:40:26 +00:00
|
|
|
#include "fdstream.h"
|
2011-07-04 11:06:14 +00:00
|
|
|
#include "domain_audit.h"
|
2011-06-07 13:29:08 +00:00
|
|
|
#include "domain_nwfilter.h"
|
2013-01-11 13:54:15 +00:00
|
|
|
#include "nwfilter_conf.h"
|
2011-10-04 12:47:26 +00:00
|
|
|
#include "network/bridge_driver.h"
|
2012-11-28 13:26:52 +00:00
|
|
|
#include "virinitctl.h"
|
2011-11-02 15:53:39 +00:00
|
|
|
#include "virnetdev.h"
|
2012-02-10 21:09:00 +00:00
|
|
|
#include "virnetdevtap.h"
|
Implement the core API to suspend/resume the host
Add the core functions that implement the functionality of the API.
Suspend is done by using an asynchronous mechanism so that we can return
the status to the caller before the host gets suspended. This asynchronous
operation is achieved by suspending the host in a separate thread of
execution. However, returning the status to the caller is only best-effort,
but not guaranteed.
To resume the host, an RTC alarm is set up (based on how long we want to
suspend) before suspending the host. When this alarm fires, the host
gets woken up.
Suspend-to-RAM operation on a host running Linux can take upto more than 20
seconds, depending on the load of the system. (Freezing of tasks, an operation
preceding any suspend operation, is given up after a 20 second timeout).
And Suspend-to-Disk can take even more time, considering the time required
for compaction, creating the memory image and writing it to disk etc.
So, we do not allow the user to specify a suspend duration of less than 60
seconds, to be on the safer side, since we don't want to prematurely declare
failure when we only had to wait for some more time.
2011-11-29 09:07:38 +00:00
|
|
|
#include "virnodesuspend.h"
|
2012-12-21 14:22:31 +00:00
|
|
|
#include "virprocess.h"
|
2011-11-29 12:33:23 +00:00
|
|
|
#include "virtime.h"
|
2012-01-07 12:47:43 +00:00
|
|
|
#include "virtypedparam.h"
|
2012-02-24 18:48:55 +00:00
|
|
|
#include "viruri.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2013-04-23 10:56:22 +00:00
|
|
|
#include "viraccessapicheck.h"
|
|
|
|
#include "viraccessapichecklxc.h"
|
2014-03-05 10:49:58 +00:00
|
|
|
#include "virhostdev.h"
|
2014-11-18 23:55:48 +00:00
|
|
|
#include "netdev_bandwidth_conf.h"
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_LXC
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("lxc.lxc_driver");
|
2011-05-05 20:35:00 +00:00
|
|
|
|
2010-10-12 16:39:05 +00:00
|
|
|
#define LXC_NB_MEM_PARAM 3
|
2014-02-14 17:49:03 +00:00
|
|
|
#define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
|
2010-10-12 16:39:05 +00:00
|
|
|
|
2014-02-14 17:49:02 +00:00
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcStateInitialize(bool privileged,
|
|
|
|
virStateInhibitCallback callback,
|
|
|
|
void *opaque);
|
|
|
|
static int lxcStateCleanup(void);
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr lxc_driver = NULL;
|
2008-03-21 15:03:37 +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
|
|
|
/* callbacks for nwfilter */
|
|
|
|
static int
|
2013-10-03 11:51:48 +00:00
|
|
|
lxcVMFilterRebuild(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
|
|
|
{
|
2013-01-11 13:54:15 +00:00
|
|
|
return virDomainObjListForEach(lxc_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
|
|
|
|
lxcVMDriverLock(void)
|
|
|
|
{
|
|
|
|
lxcDriverLock(lxc_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lxcVMDriverUnlock(void)
|
|
|
|
{
|
|
|
|
lxcDriverUnlock(lxc_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static virNWFilterCallbackDriver lxcCallbackDriver = {
|
|
|
|
.name = "LXC",
|
|
|
|
.vmFilterRebuild = lxcVMFilterRebuild,
|
|
|
|
.vmDriverLock = lxcVMDriverLock,
|
|
|
|
.vmDriverUnlock = lxcVMDriverUnlock,
|
|
|
|
};
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
/**
|
|
|
|
* lxcDomObjFromDomain:
|
|
|
|
* @domain: Domain pointer that has to be looked up
|
|
|
|
*
|
|
|
|
* This function looks up @domain and returns the appropriate
|
|
|
|
* virDomainObjPtr.
|
|
|
|
*
|
|
|
|
* Returns the domain object which is locked on success, NULL
|
|
|
|
* otherwise.
|
|
|
|
*/
|
|
|
|
static virDomainObjPtr
|
|
|
|
lxcDomObjFromDomain(virDomainPtr domain)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
virLXCDriverPtr driver = domain->conn->privateData;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
|
|
|
|
if (!vm) {
|
|
|
|
virUUIDFormat(domain->uuid, uuidstr);
|
|
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
|
_("no domain with matching uuid '%s' (%s)"),
|
|
|
|
uuidstr, domain->name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
/* Functions */
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static virDrvOpenStatus lxcConnectOpen(virConnectPtr conn,
|
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
|
|
|
unsigned int flags)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2011-07-06 22:33:53 +00:00
|
|
|
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
/* Verify uri was specified */
|
2008-11-17 11:44:51 +00:00
|
|
|
if (conn->uri == NULL) {
|
2009-06-12 12:06:15 +00:00
|
|
|
if (lxc_driver == NULL)
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
2009-01-30 16:51:33 +00:00
|
|
|
|
Centralize error reporting for URI parsing/formatting problems
Move error reporting out of the callers, into virURIParse
and virURIFormat, to get consistency.
* include/libvirt/virterror.h, src/util/virterror.c: Add VIR_FROM_URI
* src/util/viruri.c, src/util/viruri.h: Add error reporting
* src/esx/esx_driver.c, src/libvirt.c, src/libxl/libxl_driver.c,
src/lxc/lxc_driver.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/qemu/qemu_migration.c,
src/remote/remote_driver.c, src/uml/uml_driver.c,
src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xen/xen_driver.c,
src/xen/xend_internal.c, tests/viruritest.c: Remove error
reporting
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-03-20 12:16:54 +00:00
|
|
|
if (!(conn->uri = virURIParse("lxc:///")))
|
2008-11-17 11:44:51 +00:00
|
|
|
return VIR_DRV_OPEN_ERROR;
|
2009-06-12 12:06:15 +00:00
|
|
|
} else {
|
|
|
|
if (conn->uri->scheme == NULL ||
|
|
|
|
STRNEQ(conn->uri->scheme, "lxc"))
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
|
|
|
|
|
|
|
/* Leave for remote driver */
|
|
|
|
if (conn->uri->server != NULL)
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
|
|
|
|
|
|
|
/* If path isn't '/' then they typoed, tell them correct path */
|
2010-02-11 15:00:25 +00:00
|
|
|
if (conn->uri->path != NULL &&
|
|
|
|
STRNEQ(conn->uri->path, "/")) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unexpected LXC URI path '%s', try lxc:///"),
|
|
|
|
conn->uri->path);
|
2009-06-12 12:06:15 +00:00
|
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
}
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2009-06-12 12:06:15 +00:00
|
|
|
/* URI was good, but driver isn't active */
|
|
|
|
if (lxc_driver == NULL) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("lxc state driver is not active"));
|
2009-06-12 12:06:15 +00:00
|
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2009-01-30 16:51:33 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectOpenEnsureACL(conn) < 0)
|
|
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
|
2008-03-27 09:34:06 +00:00
|
|
|
conn->privateData = lxc_driver;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcConnectClose(virConnectPtr conn)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2009-07-06 15:04:36 +00:00
|
|
|
|
2013-07-15 17:08:11 +00:00
|
|
|
virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
|
2008-03-27 09:34:06 +00:00
|
|
|
conn->privateData = NULL;
|
|
|
|
return 0;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
{
|
|
|
|
/* Trivially secure, since always inside the daemon */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
{
|
|
|
|
/* Not encrypted, but remote driver takes care of that */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
|
2011-09-23 06:56:13 +00:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static char *lxcConnectGetCapabilities(virConnectPtr conn) {
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps;
|
2009-06-03 13:29:23 +00:00
|
|
|
char *xml;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2013-07-17 07:20:26 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
2013-07-15 09:43:10 +00:00
|
|
|
return NULL;
|
|
|
|
|
2014-06-27 07:55:44 +00:00
|
|
|
xml = virCapabilitiesFormatXML(caps);
|
2009-06-03 13:29:23 +00:00
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2009-06-03 13:29:23 +00:00
|
|
|
return xml;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
|
|
|
|
int id)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainPtr dom = NULL;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
vm = virDomainObjListFindByID(driver->domains, id);
|
2008-12-04 21:12:41 +00:00
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
if (!vm) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
|
_("No domain with matching id %d"), id);
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2008-12-04 21:11:41 +00:00
|
|
|
if (dom)
|
2008-03-21 15:03:37 +00:00
|
|
|
dom->id = vm->def->id;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2008-03-21 15:03:37 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
|
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainPtr dom = NULL;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
vm = virDomainObjListFindByUUID(driver->domains, uuid);
|
2008-12-04 21:12:41 +00:00
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
if (!vm) {
|
2010-05-03 11:59:03 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
|
_("No domain with matching uuid '%s'"), uuidstr);
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2008-12-04 21:11:41 +00:00
|
|
|
if (dom)
|
2008-03-21 15:03:37 +00:00
|
|
|
dom->id = vm->def->id;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2008-03-21 15:03:37 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
|
|
|
|
const char *name)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainPtr dom = NULL;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
vm = virDomainObjListFindByName(driver->domains, name);
|
2008-03-21 15:03:37 +00:00
|
|
|
if (!vm) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
|
|
_("No domain with matching name '%s'"), name);
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2008-12-04 21:11:41 +00:00
|
|
|
if (dom)
|
2008-03-21 15:03:37 +00:00
|
|
|
dom->id = vm->def->id;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2015-04-23 16:00:01 +00:00
|
|
|
virDomainObjEndAPI(&vm);
|
2008-03-21 15:03:37 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
|
|
|
|
static int lxcDomainIsActive(virDomainPtr dom)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj;
|
|
|
|
int ret = -1;
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(obj = lxcDomObjFromDomain(dom)))
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
goto cleanup;
|
2013-04-23 10:56:22 +00:00
|
|
|
|
|
|
|
if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
ret = virDomainObjIsActive(obj);
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
if (obj)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(obj);
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcDomainIsPersistent(virDomainPtr dom)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj;
|
|
|
|
int ret = -1;
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(obj = lxcDomObjFromDomain(dom)))
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
goto cleanup;
|
2013-04-23 10:56:22 +00:00
|
|
|
|
|
|
|
if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
ret = obj->persistent;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
if (obj)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(obj);
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-11-24 07:43:15 +00:00
|
|
|
static int lxcDomainIsUpdated(virDomainPtr dom)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj;
|
|
|
|
int ret = -1;
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(obj = lxcDomObjFromDomain(dom)))
|
2010-11-24 07:43:15 +00:00
|
|
|
goto cleanup;
|
2013-04-23 10:56:22 +00:00
|
|
|
|
|
|
|
if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-11-24 07:43:15 +00:00
|
|
|
ret = obj->updated;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2010-11-24 07:43:15 +00:00
|
|
|
if (obj)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(obj);
|
2010-11-24 07:43:15 +00:00
|
|
|
return ret;
|
|
|
|
}
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
|
2014-03-18 08:18:09 +00:00
|
|
|
static int lxcConnectListDomains(virConnectPtr conn, int *ids, int nids)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr 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-10-10 14:20:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectListDomainsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-06-24 16:49:47 +00:00
|
|
|
n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
|
|
|
|
virConnectListDomainsCheckACL, conn);
|
2008-10-10 14:20:37 +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-03-21 15:03:37 +00:00
|
|
|
}
|
2008-12-04 21:11:41 +00:00
|
|
|
|
2014-03-18 08:18:09 +00:00
|
|
|
static int lxcConnectNumOfDomains(virConnectPtr conn)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr 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-10-10 14:20:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectNumOfDomainsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-06-24 16:49:47 +00:00
|
|
|
n = virDomainObjListNumOfDomains(driver->domains, true,
|
|
|
|
virConnectNumOfDomainsCheckACL, conn);
|
2008-10-10 14:20:37 +00:00
|
|
|
|
2008-08-13 12:50:55 +00:00
|
|
|
return n;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcConnectListDefinedDomains(virConnectPtr conn,
|
2014-03-18 08:18:09 +00:00
|
|
|
char **const names, int nnames)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr 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-10-10 14:20:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-06-24 16:49:47 +00:00
|
|
|
n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
|
|
|
|
virConnectListDefinedDomainsCheckACL, conn);
|
2008-10-10 14:20:37 +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-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-18 08:18:09 +00:00
|
|
|
static int lxcConnectNumOfDefinedDomains(virConnectPtr conn)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr 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-10-10 14:20:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-06-24 16:49:47 +00:00
|
|
|
n = virDomainObjListNumOfDomains(driver->domains, false,
|
|
|
|
virConnectNumOfDefinedDomainsCheckACL, conn);
|
2008-10-10 14:20:37 +00:00
|
|
|
|
2008-08-13 12:50:55 +00:00
|
|
|
return n;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2008-08-13 12:50:55 +00:00
|
|
|
|
|
|
|
|
2014-11-18 14:19:38 +00:00
|
|
|
static virDomainPtr
|
|
|
|
lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainDefPtr def = NULL;
|
2008-12-04 21:12:41 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainPtr dom = NULL;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
Merge virDomainObjListIsDuplicate into virDomainObjListAdd
The duplicate VM checking should be done atomically with
virDomainObjListAdd, so shoud not be a separate function.
Instead just use flags to indicate what kind of checks are
required.
This pair, used in virDomainCreateXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainRestoreFlags:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, true)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainDefineXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
0, NULL)))
goto cleanup;
2013-01-14 14:46:58 +00:00
|
|
|
virDomainDefPtr oldDef = NULL;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2014-11-18 17:34:42 +00:00
|
|
|
unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2014-11-18 17:34:42 +00:00
|
|
|
virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
|
|
|
|
parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
|
2014-11-18 14:19:38 +00:00
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
|
2014-11-18 17:34:42 +00:00
|
|
|
parse_flags)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2014-11-18 14:19:38 +00:00
|
|
|
if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-01-25 14:12:53 +00:00
|
|
|
if (virSecurityManagerVerify(driver->securityManager, def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if ((def->nets != NULL) && !(cfg->have_netns)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("System lacks NETNS support"));
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-06-26 16:08:59 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 13:55:55 +00:00
|
|
|
if (!(vm = virDomainObjListAdd(driver->domains, def,
|
2013-03-31 18:03:42 +00:00
|
|
|
driver->xmlopt,
|
2013-03-28 13:55:55 +00:00
|
|
|
0, &oldDef)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
def = NULL;
|
2008-08-20 19:42:36 +00:00
|
|
|
vm->persistent = 1;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveConfig(cfg->configDir,
|
2008-08-20 19:42:36 +00:00
|
|
|
vm->newDef ? vm->newDef : vm->def) < 0) {
|
2013-01-11 16:04:47 +00:00
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
2008-12-04 21:12:41 +00:00
|
|
|
vm = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-07-06 15:04:36 +00:00
|
|
|
VIR_DOMAIN_EVENT_DEFINED,
|
Merge virDomainObjListIsDuplicate into virDomainObjListAdd
The duplicate VM checking should be done atomically with
virDomainObjListAdd, so shoud not be a separate function.
Instead just use flags to indicate what kind of checks are
required.
This pair, used in virDomainCreateXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainRestoreFlags:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, true)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainDefineXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
0, NULL)))
goto cleanup;
2013-01-14 14:46:58 +00:00
|
|
|
!oldDef ?
|
2009-07-06 15:04:36 +00:00
|
|
|
VIR_DOMAIN_EVENT_DEFINED_ADDED :
|
|
|
|
VIR_DOMAIN_EVENT_DEFINED_UPDATED);
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2008-12-04 21:11:41 +00:00
|
|
|
if (dom)
|
2008-03-21 15:03:37 +00:00
|
|
|
dom->id = vm->def->id;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainDefFree(def);
|
Merge virDomainObjListIsDuplicate into virDomainObjListAdd
The duplicate VM checking should be done atomically with
virDomainObjListAdd, so shoud not be a separate function.
Instead just use flags to indicate what kind of checks are
required.
This pair, used in virDomainCreateXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainRestoreFlags:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, true)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainDefineXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
0, NULL)))
goto cleanup;
2013-01-14 14:46:58 +00:00
|
|
|
virDomainDefFree(oldDef);
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-07-06 15:04:36 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2008-03-21 15:03:37 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
2014-11-18 14:19:38 +00:00
|
|
|
static virDomainPtr
|
|
|
|
lxcDomainDefineXML(virConnectPtr conn, const char *xml)
|
|
|
|
{
|
|
|
|
return lxcDomainDefineXMLFlags(conn, xml, 0);
|
|
|
|
}
|
|
|
|
|
2011-07-20 03:08:21 +00:00
|
|
|
static int lxcDomainUndefineFlags(virDomainPtr dom,
|
|
|
|
unsigned int flags)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
int ret = -1;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2011-07-20 03:08:21 +00:00
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
if (!vm->persistent) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Cannot undefine transient domain"));
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-08-20 19:42:36 +00:00
|
|
|
}
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainDeleteConfig(cfg->configDir,
|
|
|
|
cfg->autostartDir,
|
2008-12-04 21:11:41 +00:00
|
|
|
vm) < 0)
|
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-07-06 15:04:36 +00:00
|
|
|
VIR_DOMAIN_EVENT_UNDEFINED,
|
|
|
|
VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
|
|
|
|
|
2011-08-19 13:47:33 +00:00
|
|
|
if (virDomainObjIsActive(vm)) {
|
|
|
|
vm->persistent = 0;
|
|
|
|
} else {
|
2013-01-11 16:04:47 +00:00
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
2011-08-19 13:47:33 +00:00
|
|
|
vm = NULL;
|
|
|
|
}
|
|
|
|
|
2008-12-04 21:11:41 +00:00
|
|
|
ret = 0;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-07-06 15:04:36 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2011-07-20 03:08:21 +00:00
|
|
|
static int lxcDomainUndefine(virDomainPtr dom)
|
|
|
|
{
|
|
|
|
return lxcDomainUndefineFlags(dom, 0);
|
|
|
|
}
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
static int lxcDomainGetInfo(virDomainPtr dom,
|
|
|
|
virDomainInfoPtr info)
|
|
|
|
{
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
2013-07-08 10:08:46 +00:00
|
|
|
int ret = -1;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-05-04 09:07:01 +00:00
|
|
|
info->state = virDomainObjGetState(vm, NULL);
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
2008-03-21 15:03:37 +00:00
|
|
|
info->cpuTime = 0;
|
2015-08-10 18:49:55 +00:00
|
|
|
info->memory = vm->def->mem.cur_balloon;
|
2008-03-21 15:03:37 +00:00
|
|
|
} else {
|
2013-03-21 14:40:29 +00:00
|
|
|
if (virCgroupGetCpuacctUsage(priv->cgroup, &(info->cpuTime)) < 0) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("Cannot read cputime for domain"));
|
2009-10-07 13:26:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetMemoryUsage(priv->cgroup, &(info->memory)) < 0) {
|
|
|
|
/* Don't fail if we can't read memory usage due to a lack of
|
|
|
|
* kernel support */
|
|
|
|
if (virLastErrorIsSystemErrno(ENOENT)) {
|
|
|
|
virResetLastError();
|
2010-10-15 08:01:38 +00:00
|
|
|
info->memory = 0;
|
2013-07-08 10:08:46 +00:00
|
|
|
} else {
|
2010-10-15 08:01:38 +00:00
|
|
|
goto cleanup;
|
2013-07-08 10:08:46 +00:00
|
|
|
}
|
2009-03-06 14:44:04 +00:00
|
|
|
}
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2015-02-17 17:01:09 +00:00
|
|
|
info->maxMem = virDomainDefGetMemoryActual(vm->def);
|
2012-05-29 07:12:32 +00:00
|
|
|
info->nrVirtCpu = vm->def->vcpus;
|
2008-12-04 21:11:41 +00:00
|
|
|
ret = 0;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2011-05-02 09:35:29 +00:00
|
|
|
static int
|
|
|
|
lxcDomainGetState(virDomainPtr dom,
|
|
|
|
int *state,
|
|
|
|
int *reason,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2011-05-02 09:35:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-05-04 09:07:01 +00:00
|
|
|
*state = virDomainObjGetState(vm, reason);
|
2011-05-02 09:35:29 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2011-05-02 09:35:29 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2011-05-02 09:35:29 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static char *lxcDomainGetOSType(virDomainPtr dom)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
char *ret = NULL;
|
2008-08-13 12:50:55 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-08-13 12:50:55 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-04-17 00:11:06 +00:00
|
|
|
if (VIR_STRDUP(ret, virDomainOSTypeToString(vm->def->os.type)) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
2009-11-08 21:08:54 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 13:26:23 +00:00
|
|
|
/* 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
|
|
|
|
lxcDomainGetMaxMemory(virDomainPtr dom)
|
|
|
|
{
|
2009-10-07 13:26:23 +00:00
|
|
|
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;
|
2009-10-07 13:26:23 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-10-07 13:26:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-02-17 17:01:09 +00:00
|
|
|
ret = virDomainDefGetMemoryActual(vm->def);
|
2009-10-07 13:26:23 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-10-07 13:26:23 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-10-07 13:26:23 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-07-11 09:26:14 +00:00
|
|
|
static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
|
|
|
|
unsigned int flags)
|
2014-03-18 08:18:09 +00:00
|
|
|
{
|
2009-10-07 13:26:23 +00:00
|
|
|
virDomainObjPtr vm;
|
2014-07-11 09:26:14 +00:00
|
|
|
virDomainDefPtr persistentDef = NULL;
|
|
|
|
virCapsPtr caps = NULL;
|
2009-10-07 13:26:23 +00:00
|
|
|
int ret = -1;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2014-07-11 09:26:14 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
|
|
|
virLXCDriverConfigPtr cfg = NULL;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
2014-07-31 03:41:10 +00:00
|
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
|
|
VIR_DOMAIN_MEM_MAXIMUM, -1);
|
2009-10-07 13:26:23 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-10-07 13:26:23 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2014-07-11 09:26:14 +00:00
|
|
|
cfg = virLXCDriverGetConfig(driver);
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
2009-10-07 13:26:23 +00:00
|
|
|
|
2014-07-11 09:26:14 +00:00
|
|
|
if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-07-11 09:26:14 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
|
|
|
|
&persistentDef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-07-31 03:41:10 +00:00
|
|
|
if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot resize the max memory "
|
|
|
|
"on an active domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-07-11 09:26:14 +00:00
|
|
|
|
2014-07-31 03:41:10 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2015-09-16 12:25:42 +00:00
|
|
|
virDomainDefSetMemoryTotal(persistentDef, newmem);
|
2014-07-31 03:41:10 +00:00
|
|
|
if (persistentDef->mem.cur_balloon > newmem)
|
|
|
|
persistentDef->mem.cur_balloon = newmem;
|
|
|
|
if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned long oldmax = 0;
|
2009-10-07 13:26:23 +00:00
|
|
|
|
2014-07-31 03:41:10 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE)
|
2015-02-17 17:01:09 +00:00
|
|
|
oldmax = virDomainDefGetMemoryActual(vm->def);
|
2014-07-31 03:41:10 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2015-02-17 17:01:09 +00:00
|
|
|
if (!oldmax || oldmax > virDomainDefGetMemoryActual(persistentDef))
|
|
|
|
oldmax = virDomainDefGetMemoryActual(persistentDef);
|
2014-07-11 09:26:14 +00:00
|
|
|
}
|
2010-03-22 15:42:14 +00:00
|
|
|
|
2014-07-31 03:41:10 +00:00
|
|
|
if (newmem > oldmax) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
"%s", _("Cannot set memory higher than max memory"));
|
2014-07-11 09:26:14 +00:00
|
|
|
goto cleanup;
|
2014-07-31 03:41:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
if (virCgroupSetMemory(priv->cgroup, newmem) < 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("Failed to set memory for domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-10-24 09:17:20 +00:00
|
|
|
|
|
|
|
vm->def->mem.cur_balloon = newmem;
|
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
|
|
|
goto cleanup;
|
2014-07-31 03:41:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
persistentDef->mem.cur_balloon = newmem;
|
|
|
|
if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-05-03 12:02:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 13:26:23 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-10-07 13:26:23 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2014-07-11 09:26:14 +00:00
|
|
|
virObjectUnref(caps);
|
|
|
|
virObjectUnref(cfg);
|
2009-10-07 13:26:23 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-07-11 09:26:14 +00:00
|
|
|
static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
|
|
|
|
{
|
|
|
|
return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
|
|
|
|
}
|
|
|
|
|
2014-07-31 03:41:10 +00:00
|
|
|
static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
|
|
|
|
{
|
|
|
|
return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
|
|
|
|
}
|
|
|
|
|
2012-01-07 12:47:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainSetMemoryParameters(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
|
|
|
unsigned int flags)
|
2010-10-12 16:31:19 +00:00
|
|
|
{
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
virCapsPtr caps = NULL;
|
|
|
|
virDomainDefPtr vmdef = NULL;
|
2010-10-12 16:31:19 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv = NULL;
|
|
|
|
virLXCDriverConfigPtr cfg = NULL;
|
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
|
|
|
unsigned long long hard_limit;
|
|
|
|
unsigned long long soft_limit;
|
|
|
|
unsigned long long swap_hard_limit;
|
|
|
|
bool set_hard_limit = false;
|
|
|
|
bool set_soft_limit = false;
|
|
|
|
bool set_swap_hard_limit = false;
|
|
|
|
int rc;
|
2010-10-12 16:31:19 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
|
2013-05-03 13:34:10 +00:00
|
|
|
if (virTypedParamsValidate(params, nparams,
|
|
|
|
VIR_DOMAIN_MEMORY_HARD_LIMIT,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
VIR_DOMAIN_MEMORY_SOFT_LIMIT,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
NULL) < 0)
|
2012-01-07 12:47:43 +00:00
|
|
|
return -1;
|
2011-07-06 22:33:53 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2010-10-12 16:31:19 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
cfg = virLXCDriverGetConfig(driver);
|
2010-10-12 16:31:19 +00:00
|
|
|
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0 ||
|
|
|
|
!(caps = virLXCDriverGetCapabilities(driver, false)) ||
|
|
|
|
virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
|
|
|
|
vm, &flags, &vmdef) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE &&
|
|
|
|
!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cgroup memory controller is not mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE) \
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0) \
|
|
|
|
goto cleanup; \
|
|
|
|
\
|
|
|
|
if (rc == 1) \
|
|
|
|
set_ ## VALUE = true;
|
|
|
|
|
|
|
|
VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, swap_hard_limit)
|
|
|
|
VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_HARD_LIMIT, hard_limit)
|
|
|
|
VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SOFT_LIMIT, soft_limit)
|
|
|
|
|
|
|
|
#undef VIR_GET_LIMIT_PARAMETER
|
|
|
|
|
|
|
|
/* Swap hard limit must be greater than hard limit.
|
|
|
|
* Note that limit of 0 denotes unlimited */
|
|
|
|
if (set_swap_hard_limit || set_hard_limit) {
|
|
|
|
unsigned long long mem_limit = vm->def->mem.hard_limit;
|
|
|
|
unsigned long long swap_limit = vm->def->mem.swap_hard_limit;
|
|
|
|
|
|
|
|
if (set_swap_hard_limit)
|
|
|
|
swap_limit = swap_hard_limit;
|
|
|
|
|
|
|
|
if (set_hard_limit)
|
|
|
|
mem_limit = hard_limit;
|
|
|
|
|
2015-03-02 19:04:12 +00:00
|
|
|
if (mem_limit > swap_limit) {
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("memory hard_limit tunable value must be lower "
|
|
|
|
"than or equal to swap_hard_limit"));
|
|
|
|
goto cleanup;
|
2010-10-12 16:31:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
#define LXC_SET_MEM_PARAMETER(FUNC, VALUE) \
|
|
|
|
if (set_ ## VALUE) { \
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) { \
|
|
|
|
if ((rc = FUNC(priv->cgroup, VALUE)) < 0) { \
|
|
|
|
virReportSystemError(-rc, _("unable to set memory %s tunable"), \
|
|
|
|
#VALUE); \
|
|
|
|
\
|
|
|
|
goto cleanup; \
|
|
|
|
} \
|
|
|
|
vm->def->mem.VALUE = VALUE; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) \
|
|
|
|
vmdef->mem.VALUE = VALUE; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Soft limit doesn't clash with the others */
|
|
|
|
LXC_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
|
|
|
|
|
|
|
|
/* set hard limit before swap hard limit if decreasing it */
|
2015-03-02 19:04:12 +00:00
|
|
|
if (vm->def->mem.hard_limit > hard_limit) {
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
LXC_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
|
|
|
|
/* inhibit changing the limit a second time */
|
|
|
|
set_hard_limit = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
LXC_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
|
|
|
|
|
|
|
|
/* otherwise increase it after swap hard limit */
|
|
|
|
LXC_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
|
|
|
|
|
|
|
|
#undef LXC_SET_MEM_PARAMETER
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
|
|
|
|
virDomainSaveConfig(cfg->configDir, vmdef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2010-10-12 16:31:19 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
Fix crash in lxcDomainSetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain> --hard-limit 133T'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 26826)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf718) at util/vircgroup.c:1764
#1 0x00007ffff70e9206 in virCgroupSetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffe409f360 "1073741824")
at util/vircgroup.c:669
#2 0x00007ffff70e98b4 in virCgroupSetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=1073741824) at util/vircgroup.c:740
#3 0x00007ffff70ee518 in virCgroupSetMemory (group=0x0, kb=1048576) at util/vircgroup.c:1904
#4 0x00007ffff70ee675 in virCgroupSetMemoryHardLimit (group=0x0, kb=1048576)
at util/vircgroup.c:1944
#5 0x00005555557d54c8 in lxcDomainSetMemoryParameters (dom=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at lxc/lxc_driver.c:774
#6 0x00007ffff72c20f9 in virDomainSetMemoryParameters (domain=0x7fffe40cc420,
params=0x7fffe409f100, nparams=1, flags=0) at libvirt.c:4051
#7 0x000055555561365f in remoteDispatchDomainSetMemoryParameters (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510)
at remote_dispatch.h:7621
#8 0x00005555556133fd in remoteDispatchDomainSetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ec4b10, msg=0x555555eb94e0, rerr=0x7fffec8bfb70, args=0x7fffe40b8510,
ret=0x7fffe40b84f0) at remote_dispatch.h:7591
#9 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:435
#10 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ec4b10, msg=0x555555eb94e0)
at rpc/virnetserverprogram.c:305
#11 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ec4b10,
prog=0x555555ec3ae0, msg=0x555555eb94e0) at rpc/virnetserver.c:165
#12 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ec3e30, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#13 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#14 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#15 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#16 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:12 +00:00
|
|
|
virObjectUnref(caps);
|
|
|
|
virObjectUnref(cfg);
|
2010-10-12 16:31:19 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-07 12:47:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainGetMemoryParameters(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int *nparams,
|
|
|
|
unsigned int flags)
|
2010-10-12 16:39:05 +00:00
|
|
|
{
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
virCapsPtr caps = NULL;
|
|
|
|
virDomainDefPtr vmdef = NULL;
|
2010-10-12 16:39:05 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv = NULL;
|
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2011-01-13 09:18:11 +00:00
|
|
|
unsigned long long val;
|
2010-10-12 16:39:05 +00:00
|
|
|
int ret = -1;
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
size_t i;
|
2010-10-12 16:39:05 +00:00
|
|
|
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
2014-06-24 09:44:18 +00:00
|
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
|
|
VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
|
|
|
|
|
|
/* We don't return strings, and thus trivially support this flag. */
|
|
|
|
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
2011-07-06 22:33:53 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2010-10-12 16:39:05 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
2010-10-12 16:39:05 +00:00
|
|
|
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0 ||
|
|
|
|
!(caps = virLXCDriverGetCapabilities(driver, false)) ||
|
|
|
|
virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
|
|
|
|
vm, &flags, &vmdef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE &&
|
|
|
|
!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cgroup memory controller is not mounted"));
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
}
|
2013-04-23 10:56:22 +00:00
|
|
|
|
2010-10-12 16:39:05 +00:00
|
|
|
if ((*nparams) == 0) {
|
|
|
|
/* Current number of memory parameters supported by cgroups */
|
|
|
|
*nparams = LXC_NB_MEM_PARAM;
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-11-02 17:50:08 +00:00
|
|
|
for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
|
2011-05-26 17:39:04 +00:00
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
2010-10-12 16:39:05 +00:00
|
|
|
val = 0;
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
switch (i) {
|
2010-10-12 16:39:05 +00:00
|
|
|
case 0: /* fill memory hard limit here */
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
val = vmdef->mem.hard_limit;
|
|
|
|
} else if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0) {
|
2010-11-06 17:52:00 +00:00
|
|
|
goto cleanup;
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
}
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, val) < 0)
|
2010-11-06 17:52:00 +00:00
|
|
|
goto cleanup;
|
2010-10-12 16:39:05 +00:00
|
|
|
break;
|
|
|
|
case 1: /* fill memory soft limit here */
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
val = vmdef->mem.soft_limit;
|
|
|
|
} else if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0) {
|
2010-11-06 17:52:00 +00:00
|
|
|
goto cleanup;
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
}
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, val) < 0)
|
2010-11-06 17:52:00 +00:00
|
|
|
goto cleanup;
|
2010-10-12 16:39:05 +00:00
|
|
|
break;
|
|
|
|
case 2: /* fill swap hard limit here */
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
val = vmdef->mem.swap_hard_limit;
|
|
|
|
} else if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
|
2010-11-06 17:52:00 +00:00
|
|
|
goto cleanup;
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
}
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(param,
|
|
|
|
VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, val) < 0)
|
2010-11-06 17:52:00 +00:00
|
|
|
goto cleanup;
|
2010-10-12 16:39:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-02 17:50:08 +00:00
|
|
|
if (*nparams > LXC_NB_MEM_PARAM)
|
|
|
|
*nparams = LXC_NB_MEM_PARAM;
|
2010-11-06 17:52:00 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2010-10-12 16:39:05 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
The function doesn't check whether the request is made for active or
inactive domain. Thus when the domain is not running it still tries
accessing non-existing cgroups (priv->cgroup, which is NULL).
I re-made the function in order for it to work the same way it's qemu
counterpart does.
Reproducer:
1) Define an LXC domain
2) Do 'virsh memtune <domain>'
Backtrace:
Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
#0 0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
#1 0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
#2 0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
#3 0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
at util/vircgroup.c:1962
#4 0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
#5 0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
#6 0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote.c:1895
#7 0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
ret=0x7fffd4002420) at remote_dispatch.h:4050
#8 0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:435
#9 0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
at rpc/virnetserverprogram.c:305
#10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
#11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
at rpc/virnetserver.c:186
#12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
#13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
#14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
#15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2013-12-09 10:15:11 +00:00
|
|
|
virObjectUnref(caps);
|
2010-10-12 16:39:05 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-05-06 19:53:10 +00:00
|
|
|
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
|
2011-07-06 20:40:19 +00:00
|
|
|
unsigned int flags)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
char *ret = NULL;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2011-07-13 22:24:38 +00:00
|
|
|
/* Flags checked by virDomainDefFormat */
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
|
2008-12-04 21:11:41 +00:00
|
|
|
vm->newDef ? vm->newDef : vm->def,
|
2014-11-18 16:44:00 +00:00
|
|
|
virDomainDefFormatConvertXMLFlags(flags));
|
2008-12-04 21:11:41 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2014-02-05 14:10:00 +00:00
|
|
|
static char *lxcConnectDomainXMLFromNative(virConnectPtr conn,
|
|
|
|
const char *nativeFormat,
|
|
|
|
const char *nativeConfig,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
char *xml = NULL;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
|
|
|
|
if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (STRNEQ(nativeFormat, LXC_CONFIG_FORMAT)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unsupported config type %s"), nativeFormat);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(def = lxcParseConfigString(nativeConfig)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
xml = virDomainDefFormat(def, 0);
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-02-05 14:10:00 +00:00
|
|
|
virDomainDefFree(def);
|
|
|
|
return xml;
|
|
|
|
}
|
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
/**
|
2013-10-15 12:44:06 +00:00
|
|
|
* lxcDomainCreateWithFiles:
|
2008-04-10 07:30:52 +00:00
|
|
|
* @dom: domain to start
|
2010-06-10 15:55:36 +00:00
|
|
|
* @flags: Must be 0 for now
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
|
|
|
* Looks up domain and starts it.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2013-07-09 17:15:45 +00:00
|
|
|
static int lxcDomainCreateWithFiles(virDomainPtr dom,
|
|
|
|
unsigned int nfiles,
|
|
|
|
int *files,
|
|
|
|
unsigned int flags)
|
2008-04-10 07:30:52 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
int ret = -1;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2011-07-13 11:21:54 +00:00
|
|
|
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
|
2010-06-10 15:55:36 +00:00
|
|
|
|
2014-01-22 17:28:29 +00:00
|
|
|
virNWFilterReadLockFilterUpdates();
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-04-10 07:30:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-09 17:15:45 +00:00
|
|
|
if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if ((vm->def->nets != NULL) && !(cfg->have_netns)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("System lacks NETNS support"));
|
2008-08-13 12:50:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-05-03 12:04:44 +00:00
|
|
|
if (virDomainObjIsActive(vm)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is already running"));
|
2010-05-03 12:04:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-07-13 11:49:24 +00:00
|
|
|
ret = virLXCProcessStart(dom->conn, driver, vm,
|
2013-07-09 17:15:45 +00:00
|
|
|
nfiles, files,
|
2012-07-13 11:49:24 +00:00
|
|
|
(flags & VIR_DOMAIN_START_AUTODESTROY),
|
|
|
|
VIR_DOMAIN_RUNNING_BOOTED);
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2011-07-04 11:06:14 +00:00
|
|
|
if (ret == 0) {
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-07-06 15:04:36 +00:00
|
|
|
VIR_DOMAIN_EVENT_STARTED,
|
|
|
|
VIR_DOMAIN_EVENT_STARTED_BOOTED);
|
2011-07-04 11:06:14 +00:00
|
|
|
virDomainAuditStart(vm, "booted", true);
|
|
|
|
} else {
|
|
|
|
virDomainAuditStart(vm, "booted", false);
|
|
|
|
}
|
2009-07-06 15:04:36 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-07-06 15:04:36 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2014-01-22 17:28:29 +00:00
|
|
|
virNWFilterUnlockFilterUpdates();
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
2010-06-10 15:55:36 +00:00
|
|
|
/**
|
2013-04-23 12:50:18 +00:00
|
|
|
* lxcDomainCreate:
|
2010-06-10 15:55:36 +00:00
|
|
|
* @dom: domain to start
|
|
|
|
*
|
|
|
|
* Looks up domain and starts it.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcDomainCreate(virDomainPtr dom)
|
2010-06-10 15:55:36 +00:00
|
|
|
{
|
2013-07-09 17:15:45 +00:00
|
|
|
return lxcDomainCreateWithFiles(dom, 0, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* lxcDomainCreateWithFlags:
|
|
|
|
* @dom: domain to start
|
|
|
|
*
|
|
|
|
* Looks up domain and starts it.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
|
|
|
static int lxcDomainCreateWithFlags(virDomainPtr dom,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
return lxcDomainCreateWithFiles(dom, 0, NULL, flags);
|
2010-06-10 15:55:36 +00:00
|
|
|
}
|
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
/**
|
2014-06-25 08:16:16 +00:00
|
|
|
* lxcDomainCreateXMLWithFiles:
|
2008-04-10 07:30:52 +00:00
|
|
|
* @conn: pointer to connection
|
|
|
|
* @xml: XML definition of domain
|
2014-06-25 08:16:16 +00:00
|
|
|
* @nfiles: number of file descriptors passed
|
|
|
|
* @files: list of file descriptors passed
|
|
|
|
* @flags: bitwise-OR of supported virDomainCreateFlags
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
|
|
|
* Creates a domain based on xml and starts it
|
|
|
|
*
|
2014-06-25 08:16:16 +00:00
|
|
|
* Returns a new domain object or NULL in case of failure.
|
2008-04-10 07:30:52 +00:00
|
|
|
*/
|
|
|
|
static virDomainPtr
|
2013-07-09 17:15:45 +00:00
|
|
|
lxcDomainCreateXMLWithFiles(virConnectPtr conn,
|
|
|
|
const char *xml,
|
|
|
|
unsigned int nfiles,
|
|
|
|
int *files,
|
2014-03-18 08:18:09 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2008-12-04 21:12:41 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2013-07-15 09:43:10 +00:00
|
|
|
virDomainDefPtr def = NULL;
|
2008-04-10 07:30:52 +00:00
|
|
|
virDomainPtr dom = NULL;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2014-11-18 17:34:42 +00:00
|
|
|
unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
|
|
|
|
VIR_DOMAIN_START_VALIDATE, NULL);
|
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2014-11-18 17:34:42 +00:00
|
|
|
if (flags & VIR_DOMAIN_START_VALIDATE)
|
|
|
|
parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
|
2010-05-25 17:13:13 +00:00
|
|
|
|
2014-01-22 17:28:29 +00:00
|
|
|
virNWFilterReadLockFilterUpdates();
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
|
2014-11-18 17:34:42 +00:00
|
|
|
parse_flags)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2013-07-09 17:15:45 +00:00
|
|
|
if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-01-25 14:12:53 +00:00
|
|
|
if (virSecurityManagerVerify(driver->securityManager, def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if ((def->nets != NULL) && !(cfg->have_netns)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("System lacks NETNS support"));
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
2008-08-13 12:50:55 +00:00
|
|
|
|
2013-03-28 13:55:55 +00:00
|
|
|
if (!(vm = virDomainObjListAdd(driver->domains, def,
|
2013-03-31 18:03:42 +00:00
|
|
|
driver->xmlopt,
|
Merge virDomainObjListIsDuplicate into virDomainObjListAdd
The duplicate VM checking should be done atomically with
virDomainObjListAdd, so shoud not be a separate function.
Instead just use flags to indicate what kind of checks are
required.
This pair, used in virDomainCreateXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainRestoreFlags:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, true)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainDefineXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
0, NULL)))
goto cleanup;
2013-01-14 14:46:58 +00:00
|
|
|
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
|
|
|
|
NULL)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
def = NULL;
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2012-07-13 11:49:24 +00:00
|
|
|
if (virLXCProcessStart(conn, driver, vm,
|
2013-07-09 17:15:45 +00:00
|
|
|
nfiles, files,
|
2012-07-13 11:49:24 +00:00
|
|
|
(flags & VIR_DOMAIN_START_AUTODESTROY),
|
|
|
|
VIR_DOMAIN_RUNNING_BOOTED) < 0) {
|
2011-07-04 11:06:14 +00:00
|
|
|
virDomainAuditStart(vm, "booted", false);
|
2013-01-11 16:04:47 +00:00
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
2008-12-04 21:12:41 +00:00
|
|
|
vm = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-07-06 15:04:36 +00:00
|
|
|
VIR_DOMAIN_EVENT_STARTED,
|
|
|
|
VIR_DOMAIN_EVENT_STARTED_BOOTED);
|
2011-07-04 11:06:14 +00:00
|
|
|
virDomainAuditStart(vm, "booted", true);
|
2009-07-06 15:04:36 +00:00
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
2008-12-04 21:11:41 +00:00
|
|
|
if (dom)
|
2008-04-10 07:30:52 +00:00
|
|
|
dom->id = vm->def->id;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainDefFree(def);
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-07-06 15:04:36 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2014-01-22 17:28:29 +00:00
|
|
|
virNWFilterUnlockFilterUpdates();
|
2008-04-10 07:30:52 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
2014-06-25 08:16:16 +00:00
|
|
|
/**
|
|
|
|
* lxcDomainCreateXML:
|
|
|
|
* @conn: pointer to connection
|
|
|
|
* @xml: XML definition of domain
|
|
|
|
* @flags: bitwise-OR of supported virDomainCreateFlags
|
|
|
|
*
|
|
|
|
* Creates a domain based on xml and starts it
|
|
|
|
*
|
|
|
|
* Returns a new domain object or NULL in case of failure.
|
|
|
|
*/
|
2013-07-09 17:15:45 +00:00
|
|
|
static virDomainPtr
|
|
|
|
lxcDomainCreateXML(virConnectPtr conn,
|
|
|
|
const char *xml,
|
2014-03-18 08:18:09 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-07-09 17:15:45 +00:00
|
|
|
return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-25 14:12:53 +00:00
|
|
|
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2012-01-25 14:12:53 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
memset(seclabel, 0, sizeof(*seclabel));
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2012-01-25 14:12:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-01-25 14:12:53 +00:00
|
|
|
if (!virDomainVirtTypeToString(vm->def->virtType)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown virt type in domain definition '%d'"),
|
|
|
|
vm->def->virtType);
|
2012-01-25 14:12:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Theoretically, the pid can be replaced during this operation and
|
|
|
|
* return the label of a different process. If atomicity is needed,
|
|
|
|
* further validation will be required.
|
|
|
|
*
|
|
|
|
* Comment from Dan Berrange:
|
|
|
|
*
|
|
|
|
* Well the PID as stored in the virDomainObjPtr can't be changed
|
|
|
|
* because you've got a locked object. The OS level PID could have
|
|
|
|
* exited, though and in extreme circumstances have cycled through all
|
|
|
|
* PIDs back to ours. We could sanity check that our PID still exists
|
|
|
|
* after reading the label, by checking that our FD connecting to the
|
|
|
|
* LXC monitor hasn't seen SIGHUP/ERR on poll().
|
|
|
|
*/
|
|
|
|
if (virDomainObjIsActive(vm)) {
|
2013-03-12 17:34:37 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Init pid is not yet available"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-01-25 14:12:53 +00:00
|
|
|
if (virSecurityManagerGetProcessLabel(driver->securityManager,
|
2013-03-12 17:34:37 +00:00
|
|
|
vm->def, priv->initpid, seclabel) < 0) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Failed to get security label"));
|
2012-01-25 14:12:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-01-25 14:12:53 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2012-01-25 14:12:53 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lxcNodeGetSecurityModel(virConnectPtr conn,
|
|
|
|
virSecurityModelPtr secmodel)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2012-01-25 14:12:53 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
memset(secmodel, 0, sizeof(*secmodel));
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetSecurityModelEnsureACL(conn) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-08-15 22:10:35 +00:00
|
|
|
/* we treat no driver as success, but simply return no data in *secmodel */
|
2013-07-15 09:43:10 +00:00
|
|
|
if (caps->host.nsecModels == 0
|
|
|
|
|| caps->host.secModels[0].model == NULL)
|
2012-01-25 14:12:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!virStrcpy(secmodel->model, caps->host.secModels[0].model,
|
2012-01-25 14:12:53 +00:00
|
|
|
VIR_SECURITY_MODEL_BUFLEN)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("security model string exceeds max %d bytes"),
|
|
|
|
VIR_SECURITY_MODEL_BUFLEN - 1);
|
2012-01-25 14:12:53 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!virStrcpy(secmodel->doi, caps->host.secModels[0].doi,
|
2012-01-25 14:12:53 +00:00
|
|
|
VIR_SECURITY_DOI_BUFLEN)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("security DOI string exceeds max %d bytes"),
|
|
|
|
VIR_SECURITY_DOI_BUFLEN-1);
|
2012-01-25 14:12:53 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2012-01-25 14:12:53 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-06 15:04:36 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcConnectDomainEventRegister(virConnectPtr conn,
|
|
|
|
virConnectDomainEventCallback callback,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback freecb)
|
2009-07-06 15:04:36 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2009-07-06 15:04:36 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
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)
|
|
|
|
return -1;
|
2009-07-06 15:04:36 +00:00
|
|
|
|
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
|
|
|
return 0;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
2010-03-18 14:47:07 +00:00
|
|
|
|
2009-07-06 15:04:36 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcConnectDomainEventDeregister(virConnectPtr conn,
|
|
|
|
virConnectDomainEventCallback callback)
|
2009-07-06 15:04:36 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2009-07-06 15:04:36 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
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)
|
|
|
|
return -1;
|
2009-07-06 15:04:36 +00:00
|
|
|
|
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
|
|
|
return 0;
|
2009-07-06 15:04:36 +00:00
|
|
|
}
|
|
|
|
|
2010-03-18 14:47:07 +00:00
|
|
|
|
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcConnectDomainEventRegisterAny(virConnectPtr conn,
|
|
|
|
virDomainPtr dom,
|
|
|
|
int eventID,
|
|
|
|
virConnectDomainEventGenericCallback callback,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback freecb)
|
2010-03-18 14:47:07 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2010-03-18 14:47:07 +00:00
|
|
|
int ret;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2011-12-13 11:14:46 +00:00
|
|
|
if (virDomainEventStateRegisterID(conn,
|
|
|
|
driver->domainEventState,
|
|
|
|
dom, eventID,
|
|
|
|
callback, opaque, freecb, &ret) < 0)
|
Return count of callbacks when registering callbacks
When registering a callback for a particular event some callers
need to know how many callbacks already exist for that event.
While it is possible to ask for a count, this is not free from
race conditions when threaded. Thus the API for registering
callbacks should return the count of callbacks. Also rename
virDomainEventStateDeregisterAny to virDomainEventStateDeregisterID
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Return count of callbacks when
registering callbacks
* src/libxl/libxl_driver.c, src/libxl/libxl_driver.c,
src/qemu/qemu_driver.c, src/remote/remote_driver.c,
src/remote/remote_driver.c, src/uml/uml_driver.c,
src/vbox/vbox_tmpl.c, src/xen/xen_driver.c: Update
for change in APIs
2011-12-13 23:38:54 +00:00
|
|
|
ret = -1;
|
2010-03-18 14:47:07 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
|
|
|
|
int callbackID)
|
2010-03-18 14:47:07 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2010-03-18 14:47:07 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
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)
|
|
|
|
return -1;
|
2010-03-18 14:47:07 +00:00
|
|
|
|
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
|
|
|
return 0;
|
2010-03-18 14:47:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-13 06:30:58 +00:00
|
|
|
/**
|
2011-07-20 16:51:26 +00:00
|
|
|
* lxcDomainDestroyFlags:
|
2009-11-05 12:35:13 +00:00
|
|
|
* @dom: pointer to domain to destroy
|
2014-07-04 03:09:50 +00:00
|
|
|
* @flags: extra flags; not used yet.
|
2008-05-13 06:30:58 +00:00
|
|
|
*
|
|
|
|
* Sends SIGKILL to container root process to terminate the container
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2011-07-20 16:51:26 +00:00
|
|
|
static int
|
|
|
|
lxcDomainDestroyFlags(virDomainPtr dom,
|
|
|
|
unsigned int flags)
|
2008-05-13 06:30:58 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
int ret = -1;
|
2012-07-17 10:55:38 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2008-05-13 06:30:58 +00:00
|
|
|
|
2011-07-20 16:51:26 +00:00
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-05-13 06:30:58 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-05-03 12:04:44 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
2010-05-03 12:04:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-07-17 10:55:38 +00:00
|
|
|
priv = vm->privateData;
|
2012-07-13 11:49:24 +00:00
|
|
|
ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-07-06 15:04:36 +00:00
|
|
|
VIR_DOMAIN_EVENT_STOPPED,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
|
2012-07-17 10:55:38 +00:00
|
|
|
priv->doneStopEvent = true;
|
2011-07-04 11:06:14 +00:00
|
|
|
virDomainAuditStop(vm, "destroyed");
|
2008-12-04 21:12:41 +00:00
|
|
|
if (!vm->persistent) {
|
2013-01-11 16:04:47 +00:00
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
2008-12-04 21:12:41 +00:00
|
|
|
vm = NULL;
|
|
|
|
}
|
2008-12-04 21:11:41 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-07-06 15:04:36 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
2008-03-27 09:34:06 +00:00
|
|
|
|
2011-07-20 16:51:26 +00:00
|
|
|
/**
|
|
|
|
* lxcDomainDestroy:
|
|
|
|
* @dom: pointer to domain to destroy
|
|
|
|
*
|
|
|
|
* Sends SIGKILL to container root process to terminate the container
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lxcDomainDestroy(virDomainPtr dom)
|
|
|
|
{
|
|
|
|
return lxcDomainDestroyFlags(dom, 0);
|
|
|
|
}
|
|
|
|
|
2008-06-26 16:05:02 +00:00
|
|
|
static int lxcCheckNetNsSupport(void)
|
|
|
|
{
|
|
|
|
const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
|
|
|
|
int ip_rc;
|
|
|
|
|
2014-04-08 12:26:26 +00:00
|
|
|
if (virRun(argv, &ip_rc) < 0 || ip_rc == 255)
|
2008-08-13 10:25:34 +00:00
|
|
|
return 0;
|
2008-06-26 16:05:02 +00:00
|
|
|
|
2008-08-13 10:25:34 +00:00
|
|
|
if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
|
|
|
|
return 0;
|
2008-06-26 16:05:02 +00:00
|
|
|
|
2008-08-13 10:25:34 +00:00
|
|
|
return 1;
|
2008-06-26 16:05:02 +00:00
|
|
|
}
|
|
|
|
|
2009-07-06 15:05:32 +00:00
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
static virSecurityManagerPtr
|
|
|
|
lxcSecurityInit(virLXCDriverConfigPtr cfg)
|
2012-01-25 14:12:53 +00:00
|
|
|
{
|
2013-07-16 15:45:05 +00:00
|
|
|
VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
|
|
|
|
virSecurityManagerPtr mgr = virSecurityManagerNew(cfg->securityDriverName,
|
2012-05-10 16:49:29 +00:00
|
|
|
LXC_DRIVER_NAME,
|
2012-01-25 14:12:53 +00:00
|
|
|
false,
|
2013-07-16 15:45:05 +00:00
|
|
|
cfg->securityDefaultConfined,
|
2015-09-10 09:43:31 +00:00
|
|
|
cfg->securityRequireConfined,
|
|
|
|
true);
|
2012-01-25 14:12:53 +00:00
|
|
|
if (!mgr)
|
|
|
|
goto error;
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
return mgr;
|
2012-01-25 14:12:53 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
error:
|
2012-01-25 14:12:53 +00:00
|
|
|
VIR_ERROR(_("Failed to initialize security drivers"));
|
2013-02-05 17:54:55 +00:00
|
|
|
virObjectUnref(mgr);
|
2013-07-16 15:45:05 +00:00
|
|
|
return NULL;
|
2012-01-25 14:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcStateInitialize(bool privileged,
|
|
|
|
virStateInhibitCallback callback ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2013-10-09 10:18:15 +00:00
|
|
|
const char *ld;
|
2013-07-16 15:45:05 +00:00
|
|
|
virLXCDriverConfigPtr cfg = NULL;
|
2009-01-30 16:51:33 +00:00
|
|
|
|
|
|
|
/* Valgrind gets very annoyed when we clone containers, so
|
|
|
|
* disable LXC when under valgrind
|
|
|
|
* XXX remove this when valgrind is fixed
|
|
|
|
*/
|
2013-10-09 10:18:15 +00:00
|
|
|
ld = virGetEnvBlockSUID("LD_PRELOAD");
|
Fix return value in virStateInitialize impl for LXC
The LXC driver was mistakenly returning -1 for lxcStartup()
in scenarios that are not an error. This caused the libvirtd
to quit for unprivileged users. This fixes the return code
of LXC driver, and also adds a "name" field to the virStateDriver
struct and logging to make it easier to find these problems
in the future
* src/driver.h: Add a 'name' field to state driver to allow
easy identification during failures
* src/libvirt.c: Log name of failed driver for virStateInit
failures
* src/lxc/lxc_driver.c: Don't return a failure code for
lxcStartup() if LXC is not available on this host, simply
disable the driver.
* src/network/bridge_driver.c, src/node_device/node_device_devkit.c,
src/node_device/node_device_hal.c, src/opennebula/one_driver.c,
src/qemu/qemu_driver.c, src/remote/remote_driver.c,
src/secret/secret_driver.c, src/storage/storage_driver.c,
src/uml/uml_driver.c, src/xen/xen_driver.c: Fill in name
field in virStateDriver struct
2009-11-02 23:18:19 +00:00
|
|
|
if (ld && strstr(ld, "vgpreload")) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_INFO("Running under valgrind, disabling driver");
|
Fix return value in virStateInitialize impl for LXC
The LXC driver was mistakenly returning -1 for lxcStartup()
in scenarios that are not an error. This caused the libvirtd
to quit for unprivileged users. This fixes the return code
of LXC driver, and also adds a "name" field to the virStateDriver
struct and logging to make it easier to find these problems
in the future
* src/driver.h: Add a 'name' field to state driver to allow
easy identification during failures
* src/libvirt.c: Log name of failed driver for virStateInit
failures
* src/lxc/lxc_driver.c: Don't return a failure code for
lxcStartup() if LXC is not available on this host, simply
disable the driver.
* src/network/bridge_driver.c, src/node_device/node_device_devkit.c,
src/node_device/node_device_hal.c, src/opennebula/one_driver.c,
src/qemu/qemu_driver.c, src/remote/remote_driver.c,
src/secret/secret_driver.c, src/storage/storage_driver.c,
src/uml/uml_driver.c, src/xen/xen_driver.c: Fill in name
field in virStateDriver struct
2009-11-02 23:18:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-03-31 12:02:12 +00:00
|
|
|
|
Fix return value in virStateInitialize impl for LXC
The LXC driver was mistakenly returning -1 for lxcStartup()
in scenarios that are not an error. This caused the libvirtd
to quit for unprivileged users. This fixes the return code
of LXC driver, and also adds a "name" field to the virStateDriver
struct and logging to make it easier to find these problems
in the future
* src/driver.h: Add a 'name' field to state driver to allow
easy identification during failures
* src/libvirt.c: Log name of failed driver for virStateInit
failures
* src/lxc/lxc_driver.c: Don't return a failure code for
lxcStartup() if LXC is not available on this host, simply
disable the driver.
* src/network/bridge_driver.c, src/node_device/node_device_devkit.c,
src/node_device/node_device_hal.c, src/opennebula/one_driver.c,
src/qemu/qemu_driver.c, src/remote/remote_driver.c,
src/secret/secret_driver.c, src/storage/storage_driver.c,
src/uml/uml_driver.c, src/xen/xen_driver.c: Fill in name
field in virStateDriver struct
2009-11-02 23:18:19 +00:00
|
|
|
/* Check that the user is root, silently disable if not */
|
2009-06-12 13:20:13 +00:00
|
|
|
if (!privileged) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_INFO("Not running privileged, disabling driver");
|
Fix return value in virStateInitialize impl for LXC
The LXC driver was mistakenly returning -1 for lxcStartup()
in scenarios that are not an error. This caused the libvirtd
to quit for unprivileged users. This fixes the return code
of LXC driver, and also adds a "name" field to the virStateDriver
struct and logging to make it easier to find these problems
in the future
* src/driver.h: Add a 'name' field to state driver to allow
easy identification during failures
* src/libvirt.c: Log name of failed driver for virStateInit
failures
* src/lxc/lxc_driver.c: Don't return a failure code for
lxcStartup() if LXC is not available on this host, simply
disable the driver.
* src/network/bridge_driver.c, src/node_device/node_device_devkit.c,
src/node_device/node_device_hal.c, src/opennebula/one_driver.c,
src/qemu/qemu_driver.c, src/remote/remote_driver.c,
src/secret/secret_driver.c, src/storage/storage_driver.c,
src/uml/uml_driver.c, src/xen/xen_driver.c: Fill in name
field in virStateDriver struct
2009-11-02 23:18:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that this is a container enabled kernel */
|
|
|
|
if (lxcContainerAvailable(0) < 0) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_INFO("LXC support not available in this kernel, disabling driver");
|
Fix return value in virStateInitialize impl for LXC
The LXC driver was mistakenly returning -1 for lxcStartup()
in scenarios that are not an error. This caused the libvirtd
to quit for unprivileged users. This fixes the return code
of LXC driver, and also adds a "name" field to the virStateDriver
struct and logging to make it easier to find these problems
in the future
* src/driver.h: Add a 'name' field to state driver to allow
easy identification during failures
* src/libvirt.c: Log name of failed driver for virStateInit
failures
* src/lxc/lxc_driver.c: Don't return a failure code for
lxcStartup() if LXC is not available on this host, simply
disable the driver.
* src/network/bridge_driver.c, src/node_device/node_device_devkit.c,
src/node_device/node_device_hal.c, src/opennebula/one_driver.c,
src/qemu/qemu_driver.c, src/remote/remote_driver.c,
src/secret/secret_driver.c, src/storage/storage_driver.c,
src/uml/uml_driver.c, src/xen/xen_driver.c: Fill in name
field in virStateDriver struct
2009-11-02 23:18:19 +00:00
|
|
|
return 0;
|
2008-03-31 12:02:12 +00:00
|
|
|
}
|
|
|
|
|
2014-11-13 14:27:11 +00:00
|
|
|
if (VIR_ALLOC(lxc_driver) < 0)
|
2008-03-27 09:34:06 +00:00
|
|
|
return -1;
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&lxc_driver->lock) < 0) {
|
|
|
|
VIR_FREE(lxc_driver);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
if (!(lxc_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 cleanup;
|
|
|
|
|
2013-11-21 10:43:10 +00:00
|
|
|
lxc_driver->domainEventState = virObjectEventStateNew();
|
2011-01-06 17:42:12 +00:00
|
|
|
if (!lxc_driver->domainEventState)
|
2009-07-06 15:04:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-03 17:55:20 +00:00
|
|
|
lxc_driver->hostsysinfo = virSysinfoRead();
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (!(lxc_driver->config = cfg = virLXCDriverConfigNew()))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
cfg->log_libvirtd = 0; /* by default log to container logfile */
|
|
|
|
cfg->have_netns = lxcCheckNetNsSupport();
|
2008-03-21 15:03:37 +00:00
|
|
|
|
|
|
|
/* Call function to load lxc driver configuration information */
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virLXCLoadDriverConfig(cfg, SYSCONFDIR "/libvirt/lxc.conf") < 0)
|
2008-12-04 21:12:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
|
2012-01-25 14:12:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-03-05 10:49:58 +00:00
|
|
|
if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
|
lxc: Init activeUsbHostdevs
otherwise we crash with
#0 virUSBDeviceListFind (list=0x0, dev=dev@entry=0x8193d70) at util/virusb.c:526
#1 0xb1a4995b in virLXCPrepareHostdevUSBDevices (driver=driver@entry=0x815d9a0, name=0x815dbf8 "debian-700267", list=list@entry=0x81d8f08) at lxc/lxc_hostdev.c:88
#2 0xb1a49fce in virLXCPrepareHostUSBDevices (def=0x8193af8, driver=0x815d9a0) at lxc/lxc_hostdev.c:261
#3 virLXCPrepareHostDevices (driver=driver@entry=0x815d9a0, def=0x8193af8) at lxc/lxc_hostdev.c:328
#4 0xb1a4c5b1 in virLXCProcessStart (conn=0x817d3f8, driver=driver@entry=0x815d9a0, vm=vm@entry=0x8190908, autoDestroy=autoDestroy@entry=false, reason=reason@entry=VIR_DOMAIN_RUNNING_BOOTED)
at lxc/lxc_process.c:1068
#5 0xb1a57e00 in lxcDomainStartWithFlags (dom=dom@entry=0x815e460, flags=flags@entry=0) at lxc/lxc_driver.c:1014
#6 0xb1a57fc3 in lxcDomainStart (dom=0x815e460) at lxc/lxc_driver.c:1046
#7 0xb79c8375 in virDomainCreate (domain=domain@entry=0x815e460) at libvirt.c:8450
#8 0x08078959 in remoteDispatchDomainCreate (args=0x81920a0, rerr=0xb65c21d0, client=0xb0d00490, server=<optimized out>, msg=<optimized out>) at remote_dispatch.h:1066
#9 remoteDispatchDomainCreateHelper (server=0x80c4928, client=0xb0d00490, msg=0xb0d005b0, rerr=0xb65c21d0, args=0x81920a0, ret=0x815d208) at remote_dispatch.h:1044
#10 0xb7a36901 in virNetServerProgramDispatchCall (msg=0xb0d005b0, client=0xb0d00490, server=0x80c4928, prog=0x80c6438) at rpc/virnetserverprogram.c:432
#11 virNetServerProgramDispatch (prog=0x80c6438, server=server@entry=0x80c4928, client=0xb0d00490, msg=0xb0d005b0) at rpc/virnetserverprogram.c:305
#12 0xb7a300a7 in virNetServerProcessMsg (msg=<optimized out>, prog=<optimized out>, client=<optimized out>, srv=0x80c4928) at rpc/virnetserver.c:162
#13 virNetServerHandleJob (jobOpaque=0xb0d00510, opaque=0x80c4928) at rpc/virnetserver.c:183
#14 0xb7924f98 in virThreadPoolWorker (opaque=opaque@entry=0x80a94b0) at util/virthreadpool.c:144
#15 0xb7924515 in virThreadHelper (data=0x80a9440) at util/virthreadpthread.c:161
#16 0xb7887c39 in start_thread (arg=0xb65c2b70) at pthread_create.c:304
#17 0xb77eb78e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130
when adding a domain with a usb device. This is Debian bug
http://bugs.debian.org/700267
2013-03-09 13:51:25 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL)
|
2008-12-04 21:12:41 +00:00
|
|
|
goto cleanup;
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-03-31 18:03:42 +00:00
|
|
|
if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit()))
|
2013-03-05 15:17:24 +00:00
|
|
|
goto cleanup;
|
2009-11-26 17:56:01 +00:00
|
|
|
|
2013-07-15 17:08:11 +00:00
|
|
|
if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
|
2011-07-13 11:21:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-04-08 17:16:52 +00:00
|
|
|
if (virFileMakePath(cfg->stateDir) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mkdir %s"),
|
|
|
|
cfg->stateDir);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-31 10:03:41 +00:00
|
|
|
/* Get all the running persistent or transient configs first */
|
2013-01-11 16:04:47 +00:00
|
|
|
if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
|
2013-07-16 15:45:05 +00:00
|
|
|
cfg->stateDir,
|
2013-03-28 13:55:55 +00:00
|
|
|
NULL, 1,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps,
|
2013-03-31 18:03:42 +00:00
|
|
|
lxc_driver->xmlopt,
|
2013-01-11 16:04:47 +00:00
|
|
|
NULL, NULL) < 0)
|
2011-05-31 10:03:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
|
2011-05-31 10:03:41 +00:00
|
|
|
|
|
|
|
/* Then inactive persistent configs */
|
2013-01-11 16:04:47 +00:00
|
|
|
if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
|
2013-07-16 15:45:05 +00:00
|
|
|
cfg->configDir,
|
|
|
|
cfg->autostartDir, 0,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps,
|
2013-03-31 18:03:42 +00:00
|
|
|
lxc_driver->xmlopt,
|
2013-01-11 16:04:47 +00:00
|
|
|
NULL, NULL) < 0)
|
2008-12-04 21:12:41 +00:00
|
|
|
goto cleanup;
|
2008-08-13 12:50:55 +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
|
|
|
virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
|
2008-03-21 15:03:37 +00:00
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcStateCleanup();
|
2008-12-04 21:12:41 +00:00
|
|
|
return -1;
|
2008-03-21 15:03:37 +00:00
|
|
|
}
|
|
|
|
|
2013-07-25 12:03:38 +00:00
|
|
|
/**
|
|
|
|
* lxcStateAutoStart:
|
|
|
|
*
|
|
|
|
* Function to autostart the LXC daemons
|
|
|
|
*/
|
|
|
|
static void lxcStateAutoStart(void)
|
|
|
|
{
|
|
|
|
if (!lxc_driver)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virLXCProcessAutostartAll(lxc_driver);
|
|
|
|
}
|
|
|
|
|
2009-07-06 15:05:32 +00:00
|
|
|
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = opaque;
|
2009-07-06 15:05:32 +00:00
|
|
|
|
|
|
|
if (newVM) {
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event =
|
2013-11-21 17:03:26 +00:00
|
|
|
virDomainEventLifecycleNewFromObj(vm,
|
2009-07-06 15:05:32 +00:00
|
|
|
VIR_DOMAIN_EVENT_DEFINED,
|
|
|
|
VIR_DOMAIN_EVENT_DEFINED_ADDED);
|
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2009-07-06 15:05:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-04-23 12:50:18 +00:00
|
|
|
* lxcStateReload:
|
2009-07-06 15:05:32 +00:00
|
|
|
*
|
|
|
|
* Function to restart the LXC driver, it will recheck the configuration
|
|
|
|
* files and perform autostart
|
|
|
|
*/
|
|
|
|
static int
|
2014-03-18 08:18:09 +00:00
|
|
|
lxcStateReload(void)
|
|
|
|
{
|
2013-07-16 15:45:05 +00:00
|
|
|
virLXCDriverConfigPtr cfg = NULL;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2013-07-16 15:45:05 +00:00
|
|
|
|
2009-07-06 15:05:32 +00:00
|
|
|
if (!lxc_driver)
|
|
|
|
return 0;
|
|
|
|
|
2013-07-17 07:20:26 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
|
2013-07-15 09:43:10 +00:00
|
|
|
return -1;
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
cfg = virLXCDriverGetConfig(lxc_driver);
|
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
virDomainObjListLoadAllConfigs(lxc_driver->domains,
|
2013-07-16 15:45:05 +00:00
|
|
|
cfg->configDir,
|
|
|
|
cfg->autostartDir, 0,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps,
|
2013-03-31 18:03:42 +00:00
|
|
|
lxc_driver->xmlopt,
|
2013-01-11 16:04:47 +00:00
|
|
|
lxcNotifyLoadDomain, lxc_driver);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2009-07-06 15:05:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcStateCleanup(void)
|
2008-03-21 15:03:37 +00:00
|
|
|
{
|
2008-03-31 12:02:12 +00:00
|
|
|
if (lxc_driver == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2008-10-10 14:20:37 +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
|
|
|
virNWFilterUnRegisterCallbackDriver(&lxcCallbackDriver);
|
2013-01-11 13:54:15 +00:00
|
|
|
virObjectUnref(lxc_driver->domains);
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateFree(lxc_driver->domainEventState);
|
2009-07-06 15:04:36 +00:00
|
|
|
|
2013-07-15 17:08:11 +00:00
|
|
|
virObjectUnref(lxc_driver->closeCallbacks);
|
2011-07-13 11:21:54 +00:00
|
|
|
|
2013-04-03 17:55:20 +00:00
|
|
|
virSysinfoDefFree(lxc_driver->hostsysinfo);
|
|
|
|
|
2014-03-05 10:49:58 +00:00
|
|
|
virObjectUnref(lxc_driver->hostdevMgr);
|
2013-02-01 12:26:18 +00:00
|
|
|
virObjectUnref(lxc_driver->caps);
|
2013-02-05 17:54:55 +00:00
|
|
|
virObjectUnref(lxc_driver->securityManager);
|
2013-03-31 18:03:42 +00:00
|
|
|
virObjectUnref(lxc_driver->xmlopt);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(lxc_driver->config);
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(&lxc_driver->lock);
|
2008-12-04 21:12:41 +00:00
|
|
|
VIR_FREE(lxc_driver);
|
2008-03-27 09:34:06 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
static int
|
|
|
|
lxcConnectSupportsFeature(virConnectPtr conn, int feature)
|
|
|
|
{
|
|
|
|
if (virConnectSupportsFeatureEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (feature) {
|
|
|
|
case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
|
|
|
|
return 1;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
|
2008-09-03 17:21:27 +00:00
|
|
|
{
|
|
|
|
struct utsname ver;
|
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
uname(&ver);
|
2008-09-03 17:21:27 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectGetVersionEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2011-07-01 13:23:02 +00:00
|
|
|
if (virParseVersionString(ver.release, version, true) < 0) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
|
2008-09-03 17:21:27 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-03-27 09:34:06 +00:00
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
static char *lxcConnectGetHostname(virConnectPtr conn)
|
2013-04-26 16:39:11 +00:00
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectGetHostnameEnsureACL(conn) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2013-04-26 16:39:11 +00:00
|
|
|
return virGetHostname();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static char *lxcDomainGetSchedulerType(virDomainPtr dom,
|
|
|
|
int *nparams)
|
2008-10-08 16:28:48 +00:00
|
|
|
{
|
2011-11-10 12:16:26 +00:00
|
|
|
char *ret = NULL;
|
2013-03-21 14:40:29 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2009-11-08 21:08:54 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2013-03-21 14:40:29 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-28 19:00:59 +00:00
|
|
|
/* Domain not running, thus no cgroups - return defaults */
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
if (nparams)
|
|
|
|
*nparams = 3;
|
|
|
|
ignore_value(VIR_STRDUP(ret, "posix"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cgroup CPU controller is not mounted"));
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
if (nparams) {
|
2013-09-13 14:03:14 +00:00
|
|
|
if (virCgroupSupportsCpuBW(priv->cgroup))
|
2011-11-10 12:16:26 +00:00
|
|
|
*nparams = 3;
|
2013-09-13 14:03:14 +00:00
|
|
|
else
|
|
|
|
*nparams = 1;
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
2009-11-08 21:08:54 +00:00
|
|
|
|
2013-05-03 12:43:39 +00:00
|
|
|
ignore_value(VIR_STRDUP(ret, "posix"));
|
2009-11-08 21:08:54 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-03-21 14:40:29 +00:00
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
2011-11-10 12:16:26 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
|
|
|
|
long long *quota)
|
|
|
|
{
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
return -1;
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcSetVcpuBWLive(virCgroupPtr cgroup, unsigned long long period,
|
|
|
|
long long quota)
|
|
|
|
{
|
|
|
|
unsigned long long old_period;
|
|
|
|
|
|
|
|
if (period == 0 && quota == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (period) {
|
|
|
|
/* get old period, and we can rollback if set quota failed */
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
return -1;
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quota) {
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
|
|
|
|
goto error;
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
error:
|
2011-11-10 12:16:26 +00:00
|
|
|
if (period) {
|
2013-07-08 10:08:46 +00:00
|
|
|
virErrorPtr saved = virSaveLastError();
|
|
|
|
virCgroupSetCpuCfsPeriod(cgroup, old_period);
|
|
|
|
if (saved) {
|
|
|
|
virSetError(saved);
|
|
|
|
virFreeError(saved);
|
|
|
|
}
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
|
2011-05-17 22:33:53 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
|
|
|
unsigned int flags)
|
2008-10-08 16:28:48 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2011-11-10 12:16:26 +00:00
|
|
|
virDomainDefPtr vmdef = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
int ret = -1;
|
2011-11-10 12:16:26 +00:00
|
|
|
int rc;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
2013-05-03 13:34:10 +00:00
|
|
|
if (virTypedParamsValidate(params, nparams,
|
|
|
|
VIR_DOMAIN_SCHEDULER_CPU_SHARES,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
|
|
|
|
VIR_TYPED_PARAM_LLONG,
|
|
|
|
NULL) < 0)
|
2012-01-07 12:47:43 +00:00
|
|
|
return -1;
|
2008-12-04 21:12:41 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
|
2013-03-05 15:17:24 +00:00
|
|
|
vm, &flags, &vmdef) < 0)
|
2012-01-07 12:36:46 +00:00
|
|
|
goto cleanup;
|
2011-11-10 12:16:26 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
/* Make a copy for updated domain. */
|
2013-07-15 09:43:10 +00:00
|
|
|
vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
|
2011-11-10 12:16:26 +00:00
|
|
|
if (!vmdef)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cgroup CPU controller is not mounted"));
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2008-10-08 16:28:48 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
2011-05-26 17:39:04 +00:00
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
2010-05-11 13:51:46 +00:00
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2014-03-04 12:56:24 +00:00
|
|
|
unsigned long long val;
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-03-04 12:56:24 +00:00
|
|
|
if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
vm->def->cputune.shares = val;
|
2014-03-04 11:39:46 +00:00
|
|
|
vm->def->cputune.sharesSpecified = true;
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
vmdef->cputune.shares = params[i].value.ul;
|
2014-03-04 11:39:46 +00:00
|
|
|
vmdef->cputune.sharesSpecified = true;
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2013-03-21 14:40:29 +00:00
|
|
|
rc = lxcSetVcpuBWLive(priv->cgroup, params[i].value.ul, 0);
|
2011-11-10 12:16:26 +00:00
|
|
|
if (rc != 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (params[i].value.ul)
|
|
|
|
vm->def->cputune.period = params[i].value.ul;
|
|
|
|
}
|
|
|
|
|
2014-11-13 14:27:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG)
|
2011-11-10 12:16:26 +00:00
|
|
|
vmdef->cputune.period = params[i].value.ul;
|
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2013-03-21 14:40:29 +00:00
|
|
|
rc = lxcSetVcpuBWLive(priv->cgroup, 0, params[i].value.l);
|
2011-11-10 12:16:26 +00:00
|
|
|
if (rc != 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (params[i].value.l)
|
|
|
|
vm->def->cputune.quota = params[i].value.l;
|
|
|
|
}
|
|
|
|
|
2014-11-13 14:27:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG)
|
2011-11-10 12:16:26 +00:00
|
|
|
vmdef->cputune.quota = params[i].value.l;
|
2010-05-11 13:51:46 +00:00
|
|
|
}
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
2010-05-11 13:51:46 +00:00
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2013-07-16 15:45:05 +00:00
|
|
|
rc = virDomainSaveConfig(cfg->configDir, vmdef);
|
2011-11-10 12:16:26 +00:00
|
|
|
if (rc < 0)
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2011-03-29 13:42:54 +00:00
|
|
|
|
Merge virDomainObjListIsDuplicate into virDomainObjListAdd
The duplicate VM checking should be done atomically with
virDomainObjListAdd, so shoud not be a separate function.
Instead just use flags to indicate what kind of checks are
required.
This pair, used in virDomainCreateXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainRestoreFlags:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, true)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainDefineXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
0, NULL)))
goto cleanup;
2013-01-14 14:46:58 +00:00
|
|
|
virDomainObjAssignDef(vm, vmdef, false, NULL);
|
2011-11-10 12:16:26 +00:00
|
|
|
vmdef = NULL;
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
2011-11-10 12:16:26 +00:00
|
|
|
|
2008-12-04 21:11:41 +00:00
|
|
|
ret = 0;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2011-11-10 12:16:26 +00:00
|
|
|
virDomainDefFree(vmdef);
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-17 22:33:53 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcDomainSetSchedulerParameters(virDomainPtr domain,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams)
|
2011-05-17 22:33:53 +00:00
|
|
|
{
|
2013-04-23 12:50:18 +00:00
|
|
|
return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
|
2011-05-17 22:33:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int *nparams,
|
|
|
|
unsigned int flags)
|
2008-10-08 16:28:48 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2008-12-04 21:11:41 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2012-01-07 12:36:46 +00:00
|
|
|
virDomainDefPtr persistentDef;
|
2011-11-10 12:16:26 +00:00
|
|
|
unsigned long long shares = 0;
|
|
|
|
unsigned long long period = 0;
|
|
|
|
long long quota = 0;
|
2008-12-04 21:11:41 +00:00
|
|
|
int ret = -1;
|
2011-11-10 12:16:26 +00:00
|
|
|
int rc;
|
|
|
|
bool cpu_bw_status = false;
|
|
|
|
int saved_nparams = 0;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2011-11-10 12:16:26 +00:00
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
2014-06-24 09:44:18 +00:00
|
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
|
|
VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
|
|
|
|
|
|
/* We don't return strings, and thus trivially support this flag. */
|
|
|
|
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-09-13 14:03:14 +00:00
|
|
|
if (*nparams > 1)
|
|
|
|
cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
|
2011-11-10 12:16:26 +00:00
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
|
2013-03-05 15:17:24 +00:00
|
|
|
vm, &flags, &persistentDef) < 0)
|
2012-01-07 12:36:46 +00:00
|
|
|
goto cleanup;
|
2011-11-10 12:16:26 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2012-01-07 12:36:46 +00:00
|
|
|
shares = persistentDef->cputune.shares;
|
2013-05-28 19:00:59 +00:00
|
|
|
if (*nparams > 1) {
|
2012-01-07 12:36:46 +00:00
|
|
|
period = persistentDef->cputune.period;
|
|
|
|
quota = persistentDef->cputune.quota;
|
2013-05-28 19:00:59 +00:00
|
|
|
cpu_bw_status = true; /* Allow copy of data to params[] */
|
2011-11-10 12:16:26 +00:00
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cgroup CPU controller is not mounted"));
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
|
|
|
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
|
2008-12-04 21:11:41 +00:00
|
|
|
goto cleanup;
|
2011-11-10 12:16:26 +00:00
|
|
|
|
|
|
|
if (*nparams > 1 && cpu_bw_status) {
|
2013-03-21 14:40:29 +00:00
|
|
|
rc = lxcGetVcpuBWLive(priv->cgroup, &period, "a);
|
2011-11-10 12:16:26 +00:00
|
|
|
if (rc != 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-03-25 06:49:26 +00:00
|
|
|
out:
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(¶ms[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, shares) < 0)
|
2009-08-03 12:37:44 +00:00
|
|
|
goto cleanup;
|
2011-11-10 12:16:26 +00:00
|
|
|
saved_nparams++;
|
|
|
|
|
|
|
|
if (cpu_bw_status) {
|
|
|
|
if (*nparams > saved_nparams) {
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(¶ms[1],
|
|
|
|
VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, period) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
saved_nparams++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*nparams > saved_nparams) {
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(¶ms[2],
|
|
|
|
VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
|
|
|
|
VIR_TYPED_PARAM_LLONG, quota) < 0)
|
2011-11-10 12:16:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
saved_nparams++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*nparams = saved_nparams;
|
|
|
|
|
2008-12-04 21:11:41 +00:00
|
|
|
ret = 0;
|
2008-10-08 16:28:48 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2008-12-04 21:12:41 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2008-12-04 21:11:41 +00:00
|
|
|
return ret;
|
2008-10-08 16:28:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-17 22:33:53 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcDomainGetSchedulerParameters(virDomainPtr domain,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int *nparams)
|
2011-05-17 22:33:53 +00:00
|
|
|
{
|
2013-04-23 12:50:18 +00:00
|
|
|
return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
|
2011-05-17 22:33:53 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
static int
|
|
|
|
lxcDomainParseBlkioDeviceStr(char *blkioDeviceStr, const char *type,
|
|
|
|
virBlkioDevicePtr *dev, size_t *size)
|
|
|
|
{
|
|
|
|
char *temp;
|
|
|
|
int ndevices = 0;
|
|
|
|
int nsep = 0;
|
|
|
|
size_t i;
|
|
|
|
virBlkioDevicePtr result = NULL;
|
|
|
|
|
|
|
|
*dev = NULL;
|
|
|
|
*size = 0;
|
|
|
|
|
|
|
|
if (STREQ(blkioDeviceStr, ""))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
temp = blkioDeviceStr;
|
|
|
|
while (temp) {
|
|
|
|
temp = strchr(temp, ',');
|
|
|
|
if (temp) {
|
|
|
|
temp++;
|
|
|
|
nsep++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* A valid string must have even number of fields, hence an odd
|
|
|
|
* number of commas. */
|
|
|
|
if (!(nsep & 1))
|
2014-10-29 15:36:39 +00:00
|
|
|
goto parse_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
|
|
|
|
ndevices = (nsep + 1) / 2;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(result, ndevices) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
temp = blkioDeviceStr;
|
|
|
|
while (temp) {
|
|
|
|
char *p = temp;
|
|
|
|
|
|
|
|
/* device path */
|
|
|
|
p = strchr(p, ',');
|
|
|
|
if (!p)
|
2014-10-29 15:36:39 +00:00
|
|
|
goto parse_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
|
|
|
|
if (VIR_STRNDUP(result[i].path, temp, p - temp) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* value */
|
|
|
|
temp = p + 1;
|
|
|
|
|
|
|
|
if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
|
2014-08-19 12:54:24 +00:00
|
|
|
if (virStrToLong_uip(temp, &p, 10, &result[i].weight) < 0)
|
2014-10-29 15:36:39 +00:00
|
|
|
goto number_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
|
2014-08-19 12:54:24 +00:00
|
|
|
if (virStrToLong_uip(temp, &p, 10, &result[i].riops) < 0)
|
2014-10-29 15:36:39 +00:00
|
|
|
goto number_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
|
2014-08-19 12:54:24 +00:00
|
|
|
if (virStrToLong_uip(temp, &p, 10, &result[i].wiops) < 0)
|
2014-10-29 15:36:39 +00:00
|
|
|
goto number_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
|
2014-08-19 12:54:24 +00:00
|
|
|
if (virStrToLong_ullp(temp, &p, 10, &result[i].rbps) < 0)
|
2014-10-29 15:36:39 +00:00
|
|
|
goto number_error;
|
2014-08-20 11:00:30 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
|
2014-08-19 12:54:24 +00:00
|
|
|
if (virStrToLong_ullp(temp, &p, 10, &result[i].wbps) < 0)
|
2014-10-29 15:36:39 +00:00
|
|
|
goto number_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
} else {
|
2014-10-29 15:36:39 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unknown parameter '%s'"), type);
|
|
|
|
goto cleanup;
|
2013-12-13 03:09:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
if (*p == '\0')
|
|
|
|
break;
|
|
|
|
else if (*p != ',')
|
2014-10-29 15:36:39 +00:00
|
|
|
goto parse_error;
|
2013-12-13 03:09:01 +00:00
|
|
|
temp = p + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!i)
|
|
|
|
VIR_FREE(result);
|
|
|
|
|
|
|
|
*dev = result;
|
|
|
|
*size = i;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-10-29 15:36:39 +00:00
|
|
|
parse_error:
|
2013-12-13 03:09:01 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unable to parse blkio device '%s' '%s'"),
|
|
|
|
type, blkioDeviceStr);
|
2014-10-29 15:36:39 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
number_error:
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("invalid value '%s' for parameter '%s' of device '%s'"),
|
|
|
|
temp, type, result[i].path);
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-09-04 20:22:07 +00:00
|
|
|
if (result) {
|
|
|
|
virBlkioDeviceArrayClear(result, ndevices);
|
|
|
|
VIR_FREE(result);
|
|
|
|
}
|
2013-12-13 03:09:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainMergeBlkioDevice(virBlkioDevicePtr *dest_array,
|
|
|
|
size_t *dest_size,
|
|
|
|
virBlkioDevicePtr src_array,
|
|
|
|
size_t src_size,
|
|
|
|
const char *type)
|
|
|
|
{
|
|
|
|
size_t i, j;
|
|
|
|
virBlkioDevicePtr dest, src;
|
|
|
|
|
|
|
|
for (i = 0; i < src_size; i++) {
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
src = &src_array[i];
|
|
|
|
for (j = 0; j < *dest_size; j++) {
|
|
|
|
dest = &(*dest_array)[j];
|
|
|
|
if (STREQ(src->path, dest->path)) {
|
|
|
|
found = true;
|
|
|
|
|
2014-09-03 19:28:14 +00:00
|
|
|
if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->weight = src->weight;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->riops = src->riops;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->wiops = src->wiops;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->rbps = src->rbps;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->wbps = src->wbps;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else {
|
2013-12-13 03:09:01 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG, _("Unknown parameter %s"),
|
|
|
|
type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
if (!src->weight && !src->riops && !src->wiops && !src->rbps && !src->wbps)
|
|
|
|
continue;
|
|
|
|
if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0)
|
|
|
|
return -1;
|
|
|
|
dest = &(*dest_array)[*dest_size - 1];
|
|
|
|
|
2014-09-03 19:28:14 +00:00
|
|
|
if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->weight = src->weight;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->riops = src->riops;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->wiops = src->wiops;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->rbps = src->rbps;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
dest->wbps = src->wbps;
|
2014-09-03 19:28:14 +00:00
|
|
|
} else {
|
2013-12-13 03:09:01 +00:00
|
|
|
*dest_size = *dest_size - 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest->path = src->path;
|
|
|
|
src->path = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-10 12:35:38 +00:00
|
|
|
|
2014-02-14 17:49:03 +00:00
|
|
|
static int
|
|
|
|
lxcDomainBlockStats(virDomainPtr dom,
|
|
|
|
const char *path,
|
2014-09-16 13:19:46 +00:00
|
|
|
virDomainBlockStatsPtr stats)
|
2014-02-14 17:49:03 +00:00
|
|
|
{
|
2015-05-21 09:21:51 +00:00
|
|
|
int ret = -1;
|
2014-02-14 17:49:03 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainDiskDefPtr disk = NULL;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
|
|
|
if (virDomainBlockStatsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("blkio cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*path) {
|
|
|
|
/* empty path - return entire domain blkstats instead */
|
|
|
|
ret = virCgroupGetBlkioIoServiced(priv->cgroup,
|
|
|
|
&stats->rd_bytes,
|
|
|
|
&stats->wr_bytes,
|
|
|
|
&stats->rd_req,
|
|
|
|
&stats->wr_req);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-05-21 09:21:51 +00:00
|
|
|
if (!(disk = virDomainDiskByName(vm->def, path, false))) {
|
2014-02-14 17:49:03 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("invalid path: %s"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!disk->info.alias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing disk device alias name for %s"), disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virCgroupGetBlkioIoDeviceServiced(priv->cgroup,
|
|
|
|
disk->info.alias,
|
|
|
|
&stats->rd_bytes,
|
|
|
|
&stats->wr_bytes,
|
|
|
|
&stats->rd_req,
|
|
|
|
&stats->wr_req);
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-02-14 17:49:03 +00:00
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainBlockStatsFlags(virDomainPtr dom,
|
|
|
|
const char * path,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int * nparams,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2015-05-21 09:21:51 +00:00
|
|
|
int tmp, ret = -1;
|
2014-02-14 17:49:03 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainDiskDefPtr disk = NULL;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
long long rd_req, rd_bytes, wr_req, wr_bytes;
|
|
|
|
virTypedParameterPtr param;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
|
|
|
|
|
|
/* We don't return strings, and thus trivially support this flag. */
|
|
|
|
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
|
|
|
|
|
|
|
if (!params && !*nparams) {
|
|
|
|
*nparams = LXC_NB_DOMAIN_BLOCK_STAT_PARAM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
|
|
|
if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("blkio cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*path) {
|
|
|
|
/* empty path - return entire domain blkstats instead */
|
|
|
|
if (virCgroupGetBlkioIoServiced(priv->cgroup,
|
|
|
|
&rd_bytes,
|
|
|
|
&wr_bytes,
|
|
|
|
&rd_req,
|
|
|
|
&wr_req) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("domain stats query failed"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2015-05-21 09:21:51 +00:00
|
|
|
if (!(disk = virDomainDiskByName(vm->def, path, false))) {
|
2014-02-14 17:49:03 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("invalid path: %s"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!disk->info.alias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing disk device alias name for %s"), disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCgroupGetBlkioIoDeviceServiced(priv->cgroup,
|
|
|
|
disk->info.alias,
|
|
|
|
&rd_bytes,
|
|
|
|
&wr_bytes,
|
|
|
|
&rd_req,
|
|
|
|
&wr_req) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("domain stats query failed"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = 0;
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
if (tmp < *nparams && wr_bytes != -1) {
|
|
|
|
param = ¶ms[tmp];
|
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
|
|
|
|
VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp < *nparams && wr_req != -1) {
|
|
|
|
param = ¶ms[tmp];
|
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
|
|
|
|
VIR_TYPED_PARAM_LLONG, wr_req) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp < *nparams && rd_bytes != -1) {
|
|
|
|
param = ¶ms[tmp];
|
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
|
|
|
|
VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp < *nparams && rd_req != -1) {
|
|
|
|
param = ¶ms[tmp];
|
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
|
|
|
|
VIR_TYPED_PARAM_LLONG, rd_req) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
*nparams = tmp;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-02-14 17:49:03 +00:00
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-07 12:47:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainSetBlkioParameters(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
|
|
|
unsigned int flags)
|
2011-11-10 12:35:38 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-11-10 12:35:38 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
virDomainDefPtr persistentDef = NULL;
|
|
|
|
int ret = -1;
|
2013-12-13 03:09:01 +00:00
|
|
|
virLXCDriverConfigPtr cfg = NULL;
|
|
|
|
virCapsPtr caps = NULL;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
2013-05-03 13:34:10 +00:00
|
|
|
if (virTypedParamsValidate(params, nparams,
|
|
|
|
VIR_DOMAIN_BLKIO_WEIGHT,
|
|
|
|
VIR_TYPED_PARAM_UINT,
|
2013-12-13 03:09:01 +00:00
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
2013-05-03 13:34:10 +00:00
|
|
|
NULL) < 0)
|
2012-01-07 12:47:43 +00:00
|
|
|
return -1;
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2013-12-13 03:09:01 +00:00
|
|
|
return -1;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
2013-12-13 03:09:01 +00:00
|
|
|
cfg = virLXCDriverGetConfig(driver);
|
2011-11-10 12:35:38 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
|
|
|
|
&persistentDef) < 0)
|
2012-01-07 12:36:46 +00:00
|
|
|
goto cleanup;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("blkio cgroup isn't mounted"));
|
2011-11-10 12:35:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-12-13 03:09:01 +00:00
|
|
|
}
|
2011-11-10 12:35:38 +00:00
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = 0;
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2011-11-10 12:35:38 +00:00
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
|
|
|
|
|
|
|
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
|
|
|
|
size_t ndevices;
|
|
|
|
virBlkioDevicePtr devices = NULL;
|
|
|
|
size_t j;
|
|
|
|
|
|
|
|
if (lxcDomainParseBlkioDeviceStr(params[i].value.s,
|
|
|
|
param->field,
|
|
|
|
&devices,
|
|
|
|
&ndevices) < 0) {
|
|
|
|
ret = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
|
|
|
|
for (j = 0; j < ndevices; j++) {
|
|
|
|
if (virCgroupSetBlkioDeviceWeight(priv->cgroup,
|
|
|
|
devices[j].path,
|
2015-08-03 13:56:08 +00:00
|
|
|
devices[j].weight) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceWeight(priv->cgroup,
|
|
|
|
devices[j].path,
|
|
|
|
&devices[j].weight) < 0) {
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
|
|
|
|
for (j = 0; j < ndevices; j++) {
|
|
|
|
if (virCgroupSetBlkioDeviceReadIops(priv->cgroup,
|
|
|
|
devices[j].path,
|
2015-08-03 13:56:08 +00:00
|
|
|
devices[j].riops) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceReadIops(priv->cgroup,
|
|
|
|
devices[j].path,
|
|
|
|
&devices[j].riops) < 0) {
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
|
|
|
|
for (j = 0; j < ndevices; j++) {
|
|
|
|
if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup,
|
|
|
|
devices[j].path,
|
2015-08-03 13:56:08 +00:00
|
|
|
devices[j].wiops) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceWriteIops(priv->cgroup,
|
|
|
|
devices[j].path,
|
|
|
|
&devices[j].wiops) < 0) {
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
|
|
|
|
for (j = 0; j < ndevices; j++) {
|
|
|
|
if (virCgroupSetBlkioDeviceReadBps(priv->cgroup,
|
|
|
|
devices[j].path,
|
2015-08-03 13:56:08 +00:00
|
|
|
devices[j].rbps) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceReadBps(priv->cgroup,
|
|
|
|
devices[j].path,
|
|
|
|
&devices[j].rbps) < 0) {
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-08-20 11:00:30 +00:00
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
|
2013-12-13 03:09:01 +00:00
|
|
|
for (j = 0; j < ndevices; j++) {
|
|
|
|
if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
|
|
|
|
devices[j].path,
|
2015-08-03 13:56:08 +00:00
|
|
|
devices[j].wbps) < 0 ||
|
|
|
|
virCgroupGetBlkioDeviceWriteBps(priv->cgroup,
|
|
|
|
devices[j].path,
|
|
|
|
&devices[j].wbps) < 0) {
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, _("Unknown blkio parameter %s"),
|
|
|
|
param->field);
|
|
|
|
ret = -1;
|
|
|
|
virBlkioDeviceArrayClear(devices, ndevices);
|
|
|
|
VIR_FREE(devices);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j != ndevices ||
|
|
|
|
lxcDomainMergeBlkioDevice(&vm->def->blkio.devices,
|
|
|
|
&vm->def->blkio.ndevices,
|
|
|
|
devices, ndevices, param->field) < 0)
|
|
|
|
ret = -1;
|
|
|
|
virBlkioDeviceArrayClear(devices, ndevices);
|
|
|
|
VIR_FREE(devices);
|
2011-11-10 12:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-07 12:36:46 +00:00
|
|
|
}
|
2013-12-13 03:09:01 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
2012-01-07 12:36:46 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2011-11-10 12:35:38 +00:00
|
|
|
/* Clang can't see that if we get here, persistentDef was set. */
|
|
|
|
sa_assert(persistentDef);
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
|
|
|
|
|
|
|
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
|
|
|
|
persistentDef->blkio.weight = params[i].value.ui;
|
2013-12-13 03:09:01 +00:00
|
|
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
|
|
|
|
virBlkioDevicePtr devices = NULL;
|
|
|
|
size_t ndevices;
|
|
|
|
|
|
|
|
if (lxcDomainParseBlkioDeviceStr(params[i].value.s,
|
|
|
|
param->field,
|
|
|
|
&devices,
|
|
|
|
&ndevices) < 0) {
|
|
|
|
ret = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (lxcDomainMergeBlkioDevice(&persistentDef->blkio.devices,
|
|
|
|
&persistentDef->blkio.ndevices,
|
|
|
|
devices, ndevices, param->field) < 0)
|
|
|
|
ret = -1;
|
|
|
|
virBlkioDeviceArrayClear(devices, ndevices);
|
|
|
|
VIR_FREE(devices);
|
2011-11-10 12:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
ret = -1;
|
2011-11-10 12:35:38 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2011-11-10 12:35:38 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2011-11-10 12:35:38 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
#define LXC_NB_BLKIO_PARAM 6
|
|
|
|
|
2012-01-07 12:47:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainGetBlkioParameters(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int *nparams,
|
|
|
|
unsigned int flags)
|
2011-11-10 12:35:38 +00:00
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2013-12-13 03:09:01 +00:00
|
|
|
size_t i, j;
|
2011-11-10 12:35:38 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
virDomainDefPtr persistentDef = NULL;
|
|
|
|
unsigned int val;
|
|
|
|
int ret = -1;
|
2013-12-13 03:09:01 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
2013-12-13 03:09:01 +00:00
|
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
|
|
VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
|
|
|
|
|
|
/* We blindly return a string, and let libvirt.c and
|
|
|
|
* remote_driver.c do the filtering on behalf of older clients
|
|
|
|
* that can't parse it. */
|
|
|
|
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2013-12-13 03:09:01 +00:00
|
|
|
return -1;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-11-10 12:35:38 +00:00
|
|
|
if ((*nparams) == 0) {
|
|
|
|
/* Current number of blkio parameters supported by cgroups */
|
|
|
|
*nparams = LXC_NB_BLKIO_PARAM;
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
|
|
|
|
&persistentDef) < 0)
|
2012-01-07 12:36:46 +00:00
|
|
|
goto cleanup;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("blkio cgroup isn't mounted"));
|
2011-11-10 12:35:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
|
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
|
|
|
val = 0;
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
case 0: /* fill blkio weight here */
|
2013-07-08 10:08:46 +00:00
|
|
|
if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
|
2011-11-10 12:35:38 +00:00
|
|
|
goto cleanup;
|
2012-01-07 12:47:43 +00:00
|
|
|
if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
|
|
|
|
VIR_TYPED_PARAM_UINT, val) < 0)
|
2011-11-10 12:35:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
2013-12-13 03:09:01 +00:00
|
|
|
case 1: /* blkiotune.device_weight */
|
|
|
|
if (vm->def->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < vm->def->blkio.ndevices; j++) {
|
|
|
|
if (!vm->def->blkio.devices[j].weight)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%u",
|
|
|
|
vm->def->blkio.devices[j].path,
|
|
|
|
vm->def->blkio.devices[j].weight);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (virTypedParameterAssign(param,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
param->value.s) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: /* blkiotune.device_read_iops */
|
|
|
|
if (vm->def->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < vm->def->blkio.ndevices; j++) {
|
|
|
|
if (!vm->def->blkio.devices[j].riops)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%u",
|
|
|
|
vm->def->blkio.devices[j].path,
|
|
|
|
vm->def->blkio.devices[j].riops);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (virTypedParameterAssign(param,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
param->value.s) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: /* blkiotune.device_write_iops */
|
|
|
|
if (vm->def->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < vm->def->blkio.ndevices; j++) {
|
|
|
|
if (!vm->def->blkio.devices[j].wiops)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%u",
|
|
|
|
vm->def->blkio.devices[j].path,
|
|
|
|
vm->def->blkio.devices[j].wiops);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (virTypedParameterAssign(param,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
param->value.s) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: /* blkiotune.device_read_bps */
|
|
|
|
if (vm->def->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < vm->def->blkio.ndevices; j++) {
|
|
|
|
if (!vm->def->blkio.devices[j].rbps)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%llu",
|
|
|
|
vm->def->blkio.devices[j].path,
|
|
|
|
vm->def->blkio.devices[j].rbps);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (virTypedParameterAssign(param,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
param->value.s) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: /* blkiotune.device_write_bps */
|
|
|
|
if (vm->def->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < vm->def->blkio.ndevices; j++) {
|
|
|
|
if (!vm->def->blkio.devices[j].wbps)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%llu",
|
|
|
|
vm->def->blkio.devices[j].path,
|
|
|
|
vm->def->blkio.devices[j].wbps);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (virTypedParameterAssign(param,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
|
|
|
|
VIR_TYPED_PARAM_STRING,
|
|
|
|
param->value.s) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
2011-11-10 12:35:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
|
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
2013-12-13 03:09:01 +00:00
|
|
|
val = 0;
|
|
|
|
param->value.ui = 0;
|
|
|
|
param->type = VIR_TYPED_PARAM_UINT;
|
2011-11-10 12:35:38 +00:00
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
case 0: /* fill blkio weight here */
|
2013-12-13 03:09:01 +00:00
|
|
|
if (virStrcpyStatic(param->field, VIR_DOMAIN_BLKIO_WEIGHT) == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Field name '%s' too long"),
|
|
|
|
VIR_DOMAIN_BLKIO_WEIGHT);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
param->value.ui = persistentDef->blkio.weight;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* blkiotune.device_weight */
|
|
|
|
if (persistentDef->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < persistentDef->blkio.ndevices; j++) {
|
|
|
|
if (!persistentDef->blkio.devices[j].weight)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%u",
|
|
|
|
persistentDef->blkio.devices[j].path,
|
|
|
|
persistentDef->blkio.devices[j].weight);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
param->type = VIR_TYPED_PARAM_STRING;
|
|
|
|
if (virStrcpyStatic(param->field,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Field name '%s' too long"),
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: /* blkiotune.device_read_iops */
|
|
|
|
if (persistentDef->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < persistentDef->blkio.ndevices; j++) {
|
|
|
|
if (!persistentDef->blkio.devices[j].riops)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%u",
|
|
|
|
persistentDef->blkio.devices[j].path,
|
|
|
|
persistentDef->blkio.devices[j].riops);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
param->type = VIR_TYPED_PARAM_STRING;
|
|
|
|
if (virStrcpyStatic(param->field,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Field name '%s' too long"),
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: /* blkiotune.device_write_iops */
|
|
|
|
if (persistentDef->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < persistentDef->blkio.ndevices; j++) {
|
|
|
|
if (!persistentDef->blkio.devices[j].wiops)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%u",
|
|
|
|
persistentDef->blkio.devices[j].path,
|
|
|
|
persistentDef->blkio.devices[j].wiops);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
param->type = VIR_TYPED_PARAM_STRING;
|
|
|
|
if (virStrcpyStatic(param->field,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Field name '%s' too long"),
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS);
|
2011-11-10 12:35:38 +00:00
|
|
|
goto cleanup;
|
2013-12-13 03:09:01 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4: /* blkiotune.device_read_bps */
|
|
|
|
if (persistentDef->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < persistentDef->blkio.ndevices; j++) {
|
|
|
|
if (!persistentDef->blkio.devices[j].rbps)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%llu",
|
|
|
|
persistentDef->blkio.devices[j].path,
|
|
|
|
persistentDef->blkio.devices[j].rbps);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
param->type = VIR_TYPED_PARAM_STRING;
|
|
|
|
if (virStrcpyStatic(param->field,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Field name '%s' too long"),
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_BPS);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: /* blkiotune.device_write_bps */
|
|
|
|
if (persistentDef->blkio.ndevices > 0) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool comma = false;
|
|
|
|
|
|
|
|
for (j = 0; j < persistentDef->blkio.ndevices; j++) {
|
|
|
|
if (!persistentDef->blkio.devices[j].wbps)
|
|
|
|
continue;
|
|
|
|
if (comma)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
else
|
|
|
|
comma = true;
|
|
|
|
virBufferAsprintf(&buf, "%s,%llu",
|
|
|
|
persistentDef->blkio.devices[j].path,
|
|
|
|
persistentDef->blkio.devices[j].wbps);
|
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-12-13 03:09:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
param->value.s = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
param->type = VIR_TYPED_PARAM_STRING;
|
|
|
|
if (virStrcpyStatic(param->field,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS) == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Field name '%s' too long"),
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-11-10 12:35:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LXC_NB_BLKIO_PARAM < *nparams)
|
|
|
|
*nparams = LXC_NB_BLKIO_PARAM;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2011-11-10 12:35:38 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2011-11-10 12:35:38 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-12 13:55:44 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
static int
|
|
|
|
lxcDomainInterfaceStats(virDomainPtr dom,
|
|
|
|
const char *path,
|
2014-09-16 13:19:45 +00:00
|
|
|
virDomainInterfaceStatsPtr stats)
|
2009-11-12 13:55:44 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-11-12 13:55:44 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-11-12 13:55:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-11-12 13:55:44 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
2009-11-12 13:55:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the path is one of the domain's network interfaces. */
|
2013-05-21 08:03:33 +00:00
|
|
|
for (i = 0; i < vm->def->nnets; i++) {
|
2009-11-12 13:55:44 +00:00
|
|
|
if (vm->def->nets[i]->ifname &&
|
|
|
|
STREQ(vm->def->nets[i]->ifname, path)) {
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 0)
|
2014-07-05 15:34:39 +00:00
|
|
|
ret = virNetInterfaceStats(path, stats);
|
2009-11-12 13:55:44 +00:00
|
|
|
else
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Invalid path, '%s' is not a known interface"), path);
|
2009-11-12 13:55:44 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-11-12 13:55:44 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-11-12 13:55:44 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int
|
|
|
|
lxcDomainInterfaceStats(virDomainPtr dom,
|
|
|
|
const char *path ATTRIBUTE_UNUSED,
|
2014-09-16 13:19:45 +00:00
|
|
|
virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED)
|
2011-10-27 07:17:59 +00:00
|
|
|
{
|
2013-12-20 01:38:59 +00:00
|
|
|
virReportUnsupportedError();
|
2009-11-12 13:55:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-07-06 15:05:32 +00:00
|
|
|
static int lxcDomainGetAutostart(virDomainPtr dom,
|
2014-03-18 08:18:09 +00:00
|
|
|
int *autostart)
|
|
|
|
{
|
2009-07-06 15:05:32 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-07-06 15:05:32 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-07-06 15:05:32 +00:00
|
|
|
*autostart = vm->autostart;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-07-06 15:05:32 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2009-07-06 15:05:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lxcDomainSetAutostart(virDomainPtr dom,
|
2013-07-16 15:45:05 +00:00
|
|
|
int autostart)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2009-07-06 15:05:32 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
|
|
|
int ret = -1;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-07-16 15:45:05 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-07-06 15:05:32 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-07-06 15:05:32 +00:00
|
|
|
if (!vm->persistent) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Cannot set autostart for transient domain"));
|
2009-07-06 15:05:32 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
autostart = (autostart != 0);
|
|
|
|
|
2009-11-05 12:41:14 +00:00
|
|
|
if (vm->autostart == autostart) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-07-06 15:05:32 +00:00
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
configFile = virDomainConfigFile(cfg->configDir,
|
2009-11-05 12:41:14 +00:00
|
|
|
vm->def->name);
|
|
|
|
if (configFile == NULL)
|
|
|
|
goto cleanup;
|
2013-07-16 15:45:05 +00:00
|
|
|
autostartLink = virDomainConfigFile(cfg->autostartDir,
|
2009-11-05 12:41:14 +00:00
|
|
|
vm->def->name);
|
|
|
|
if (autostartLink == NULL)
|
|
|
|
goto cleanup;
|
2009-07-06 15:05:32 +00:00
|
|
|
|
2009-11-05 12:41:14 +00:00
|
|
|
if (autostart) {
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virFileMakePath(cfg->autostartDir) < 0) {
|
2011-07-05 21:02:53 +00:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 12:41:14 +00:00
|
|
|
_("Cannot create autostart directory %s"),
|
2013-07-16 15:45:05 +00:00
|
|
|
cfg->autostartDir);
|
2009-11-05 12:41:14 +00:00
|
|
|
goto cleanup;
|
2009-07-06 15:05:32 +00:00
|
|
|
}
|
|
|
|
|
2009-11-05 12:41:14 +00:00
|
|
|
if (symlink(configFile, autostartLink) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 12:41:14 +00:00
|
|
|
_("Failed to create symlink '%s to '%s'"),
|
|
|
|
autostartLink, configFile);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 12:41:14 +00:00
|
|
|
_("Failed to delete symlink '%s'"),
|
|
|
|
autostartLink);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-07-06 15:05:32 +00:00
|
|
|
}
|
2009-11-05 12:41:14 +00:00
|
|
|
|
|
|
|
vm->autostart = autostart;
|
2009-07-06 15:05:32 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-07-06 15:05:32 +00:00
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2009-07-06 15:05:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
static int lxcFreezeContainer(virDomainObjPtr vm)
|
2009-09-21 14:31:22 +00:00
|
|
|
{
|
|
|
|
int timeout = 1000; /* In milliseconds */
|
|
|
|
int check_interval = 1; /* In milliseconds */
|
|
|
|
int exp = 10;
|
|
|
|
int waited_time = 0;
|
|
|
|
int ret = -1;
|
|
|
|
char *state = NULL;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
2010-05-17 17:18:12 +00:00
|
|
|
|
2009-09-21 14:31:22 +00:00
|
|
|
while (waited_time < timeout) {
|
|
|
|
int r;
|
|
|
|
/*
|
|
|
|
* Writing "FROZEN" to the "freezer.state" freezes the group,
|
|
|
|
* i.e., the container, temporarily transiting "FREEZING" state.
|
|
|
|
* Once the freezing is completed, the state of the group transits
|
|
|
|
* to "FROZEN".
|
|
|
|
* (see linux-2.6/Documentation/cgroups/freezer-subsystem.txt)
|
|
|
|
*/
|
2013-03-21 14:40:29 +00:00
|
|
|
r = virCgroupSetFreezerState(priv->cgroup, "FROZEN");
|
2009-09-21 14:31:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returning EBUSY explicitly indicates that the group is
|
2014-05-13 02:15:50 +00:00
|
|
|
* being frozen but incomplete, and other errors are true
|
2009-09-21 14:31:22 +00:00
|
|
|
* errors.
|
|
|
|
*/
|
|
|
|
if (r < 0 && r != -EBUSY) {
|
|
|
|
VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (r == -EBUSY)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("Writing freezer.state gets EBUSY");
|
2009-09-21 14:31:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Unfortunately, returning 0 (success) is likely to happen
|
|
|
|
* even when the freezing has not been completed. Sometimes
|
|
|
|
* the state of the group remains "FREEZING" like when
|
|
|
|
* returning -EBUSY and even worse may never transit to
|
|
|
|
* "FROZEN" even if writing "FROZEN" again.
|
|
|
|
*
|
|
|
|
* So we don't trust the return value anyway and always
|
|
|
|
* decide that the freezing has been complete only with
|
|
|
|
* the state actually transit to "FROZEN".
|
|
|
|
*/
|
|
|
|
usleep(check_interval * 1000);
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
r = virCgroupGetFreezerState(priv->cgroup, &state);
|
2009-09-21 14:31:22 +00:00
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
VIR_DEBUG("Reading freezer.state failed with errno: %d", r);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Read freezer.state: %s", state);
|
|
|
|
|
|
|
|
if (STREQ(state, "FROZEN")) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
waited_time += check_interval;
|
|
|
|
/*
|
|
|
|
* Increasing check_interval exponentially starting with
|
|
|
|
* small initial value treats nicely two cases; One is
|
|
|
|
* a container is under no load and waiting for long period
|
|
|
|
* makes no sense. The other is under heavy load. The container
|
|
|
|
* may stay longer time in FREEZING or never transit to FROZEN.
|
|
|
|
* In that case, eager polling will just waste CPU time.
|
|
|
|
*/
|
|
|
|
check_interval *= exp;
|
|
|
|
VIR_FREE(state);
|
|
|
|
}
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("lxcFreezeContainer timeout");
|
2014-03-25 06:49:26 +00:00
|
|
|
error:
|
2009-09-21 14:31:22 +00:00
|
|
|
/*
|
|
|
|
* If timeout or an error on reading the state occurs,
|
|
|
|
* activate the group again and return an error.
|
|
|
|
* This is likely to fall the group back again gracefully.
|
|
|
|
*/
|
2013-03-21 14:40:29 +00:00
|
|
|
virCgroupSetFreezerState(priv->cgroup, "THAWED");
|
2009-09-21 14:31:22 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-09-21 14:31:22 +00:00
|
|
|
VIR_FREE(state);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lxcDomainSuspend(virDomainPtr dom)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2009-09-21 14:31:22 +00:00
|
|
|
virDomainObjPtr vm;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2009-09-21 14:31:22 +00:00
|
|
|
int ret = -1;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-07-16 15:45:05 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-04 09:07:01 +00:00
|
|
|
if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
|
2013-03-21 14:40:29 +00:00
|
|
|
if (lxcFreezeContainer(vm) < 0) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("Suspend operation failed"));
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-05-04 09:07:01 +00:00
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
|
2009-09-21 14:31:22 +00:00
|
|
|
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-09-21 14:31:22 +00:00
|
|
|
VIR_DOMAIN_EVENT_SUSPENDED,
|
|
|
|
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
|
|
|
|
}
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-09-21 14:31:22 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2009-09-21 14:31:22 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2009-09-21 14:31:22 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lxcDomainResume(virDomainPtr dom)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2009-09-21 14:31:22 +00:00
|
|
|
virDomainObjPtr vm;
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2009-09-21 14:31:22 +00:00
|
|
|
int ret = -1;
|
2013-03-21 14:40:29 +00:00
|
|
|
virLXCDomainObjPrivatePtr priv;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-07-16 15:45:05 +00:00
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
priv = vm->privateData;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-04 09:07:01 +00:00
|
|
|
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
|
2013-03-21 14:40:29 +00:00
|
|
|
if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("Resume operation failed"));
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-05-04 09:07:01 +00:00
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
|
|
|
|
VIR_DOMAIN_RUNNING_UNPAUSED);
|
2009-09-21 14:31:22 +00:00
|
|
|
|
2013-11-21 17:03:26 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm,
|
2009-09-21 14:31:22 +00:00
|
|
|
VIR_DOMAIN_EVENT_RESUMED,
|
|
|
|
VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
|
|
|
|
}
|
|
|
|
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
2009-09-21 14:31:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2009-09-21 14:31:22 +00:00
|
|
|
if (event)
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2009-09-21 14:31:22 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2009-09-21 14:31:22 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-10-22 13:40:26 +00:00
|
|
|
static int
|
|
|
|
lxcDomainOpenConsole(virDomainPtr dom,
|
2011-09-16 12:05:58 +00:00
|
|
|
const char *dev_name,
|
2010-10-22 13:40:26 +00:00
|
|
|
virStreamPtr st,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
virDomainChrDefPtr chr = NULL;
|
2011-10-20 13:57:10 +00:00
|
|
|
size_t i;
|
2010-10-22 13:40:26 +00:00
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2010-10-22 13:40:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-10-22 13:40:26 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("domain is not running"));
|
2010-10-22 13:40:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
if (dev_name) {
|
2013-05-21 08:03:33 +00:00
|
|
|
for (i = 0; i < vm->def->nconsoles; i++) {
|
2011-10-20 13:57:10 +00:00
|
|
|
if (vm->def->consoles[i]->info.alias &&
|
|
|
|
STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
|
|
|
|
chr = vm->def->consoles[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-10-22 13:40:26 +00:00
|
|
|
} else {
|
Allow multiple consoles per virtual guest
While Xen only has a single paravirt console, UML, and
QEMU both support multiple paravirt consoles. The LXC
driver can also be trivially made to support multiple
consoles. This patch extends the XML to allow multiple
<console> elements in the XML. It also makes the UML
and QEMU drivers support this config.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Allow
multiple <console> devices
* src/lxc/lxc_driver.c, src/xen/xen_driver.c,
src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c: Update for
internal API changes
* src/security/security_selinux.c, src/security/virt-aa-helper.c:
Only label consoles that aren't a copy of the serial device
* src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_process.c, src/uml/uml_conf.c,
src/uml/uml_driver.c: Support multiple console devices
* tests/qemuxml2xmltest.c, tests/qemuxml2argvtest.c: Extra
tests for multiple virtio consoles. Set QEMU_CAPS_CHARDEV
for all console /channel tests
* tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args,
tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args: Update
for correct chardev syntax
* tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args,
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml: New
test file
2011-02-23 18:27:23 +00:00
|
|
|
if (vm->def->nconsoles)
|
|
|
|
chr = vm->def->consoles[0];
|
2010-10-22 13:40:26 +00:00
|
|
|
else if (vm->def->nserials)
|
|
|
|
chr = vm->def->serials[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!chr) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot find console device '%s'"),
|
|
|
|
dev_name ? dev_name : _("default"));
|
2010-10-22 13:40:26 +00:00
|
|
|
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) {
|
2012-07-13 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2015-06-15 13:58:36 +00:00
|
|
|
_("character device %s is not using a PTY"),
|
|
|
|
dev_name ? dev_name : NULLSTR(chr->info.alias));
|
2010-10-22 13:40:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-04-05 10:27:35 +00:00
|
|
|
if (virFDStreamOpenFile(st, chr->source.data.file.path,
|
2011-08-02 17:19:53 +00:00
|
|
|
0, 0, O_RDWR) < 0)
|
2010-10-22 13:40:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2010-10-22 13:40:26 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2010-10-22 13:40:26 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-15 15:26:32 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainSendProcessSignal(virDomainPtr dom,
|
|
|
|
long long pid_value,
|
|
|
|
unsigned int signum,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
pid_t victim;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
|
|
|
if (signum >= VIR_DOMAIN_PROCESS_SIGNAL_LAST) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("signum value %d is out of range"),
|
|
|
|
signum);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2011-11-15 15:26:32 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2011-11-15 15:26:32 +00:00
|
|
|
priv = vm->privateData;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-11-15 15:26:32 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX if the kernel has /proc/$PID/ns/pid we can
|
|
|
|
* switch into container namespace & that way be
|
|
|
|
* able to kill any PID. Alternatively if there
|
|
|
|
* is a way to find a mapping of guest<->host PIDs
|
|
|
|
* we can kill that way.
|
|
|
|
*/
|
|
|
|
if (pid_value != 1) {
|
|
|
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
|
|
|
_("Only the init process may be killed"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Init pid is not yet available"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
victim = priv->initpid;
|
|
|
|
|
|
|
|
/* We're relying on fact libvirt header signal numbers
|
|
|
|
* are taken from Linux, to avoid mapping
|
|
|
|
*/
|
|
|
|
if (kill(victim, signum) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to send %d signal to process %d"),
|
|
|
|
signum, victim);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2011-11-15 15:26:32 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2011-11-15 15:26:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-11 09:04:57 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcConnectListAllDomains(virConnectPtr conn,
|
|
|
|
virDomainPtr **domains,
|
2012-06-11 09:04:57 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2012-07-13 11:56:29 +00:00
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
2012-06-11 09:04:57 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2012-08-03 15:48:05 +00:00
|
|
|
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
|
2012-06-11 09:04:57 +00:00
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectListAllDomainsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-06-24 16:49:47 +00:00
|
|
|
ret = virDomainObjListExport(driver->domains, conn, domains,
|
|
|
|
virConnectListAllDomainsCheckACL, flags);
|
2012-06-11 09:04:57 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
|
2013-12-24 05:55:51 +00:00
|
|
|
static int
|
|
|
|
lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
int *command = opaque;
|
|
|
|
return virInitctlSetRunLevel(*command);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 13:26:52 +00:00
|
|
|
static int
|
|
|
|
lxcDomainShutdownFlags(virDomainPtr dom,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2014-01-06 21:58:59 +00:00
|
|
|
int rc;
|
2012-11-28 13:26:52 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
|
|
|
|
VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2012-11-28 13:26:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
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)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-11-28 13:26:52 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->initpid == 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Init process ID is not yet known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-01-06 21:58:59 +00:00
|
|
|
if (flags == 0 ||
|
|
|
|
(flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
|
2013-12-24 05:55:51 +00:00
|
|
|
int command = VIR_INITCTL_RUNLEVEL_POWEROFF;
|
|
|
|
|
|
|
|
if ((rc = virProcessRunInMountNamespace(priv->initpid,
|
|
|
|
lxcDomainInitctlCallback,
|
|
|
|
&command)) < 0)
|
2012-11-28 13:26:52 +00:00
|
|
|
goto cleanup;
|
2014-01-06 21:58:59 +00:00
|
|
|
if (rc == 0 && flags != 0 &&
|
|
|
|
((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
|
2012-11-28 13:26:52 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
|
|
|
_("Container does not provide an initctl pipe"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-01-06 21:58:59 +00:00
|
|
|
} else {
|
|
|
|
rc = 0;
|
2012-11-28 13:26:52 +00:00
|
|
|
}
|
2013-04-03 16:00:20 +00:00
|
|
|
|
2014-01-06 21:58:59 +00:00
|
|
|
if (rc == 0 &&
|
|
|
|
(flags == 0 ||
|
|
|
|
(flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
|
2013-04-03 16:00:20 +00:00
|
|
|
if (kill(priv->initpid, SIGTERM) < 0 &&
|
|
|
|
errno != ESRCH) {
|
2012-11-28 13:26:52 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to send SIGTERM to init pid %llu"),
|
|
|
|
(unsigned long long)priv->initpid);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-28 13:26:52 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2012-11-28 13:26:52 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainShutdown(virDomainPtr dom)
|
|
|
|
{
|
|
|
|
return lxcDomainShutdownFlags(dom, 0);
|
|
|
|
}
|
|
|
|
|
2013-12-24 05:55:51 +00:00
|
|
|
|
2012-11-28 13:26:52 +00:00
|
|
|
static int
|
|
|
|
lxcDomainReboot(virDomainPtr dom,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
|
|
|
|
VIR_DOMAIN_REBOOT_SIGNAL, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2012-11-28 13:26:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
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 (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
|
2013-04-23 10:56:22 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-11-28 13:26:52 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->initpid == 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Init process ID is not yet known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags == 0 ||
|
|
|
|
(flags & VIR_DOMAIN_REBOOT_INITCTL)) {
|
2013-12-24 05:55:51 +00:00
|
|
|
int command = VIR_INITCTL_RUNLEVEL_REBOOT;
|
|
|
|
|
|
|
|
if ((rc = virProcessRunInMountNamespace(priv->initpid,
|
|
|
|
lxcDomainInitctlCallback,
|
|
|
|
&command)) < 0)
|
2012-11-28 13:26:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
if (rc == 0 && flags != 0 &&
|
|
|
|
((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
|
|
|
_("Container does not provide an initctl pipe"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == 0 &&
|
|
|
|
(flags == 0 ||
|
|
|
|
(flags & VIR_DOMAIN_REBOOT_SIGNAL))) {
|
|
|
|
if (kill(priv->initpid, SIGHUP) < 0 &&
|
|
|
|
errno != ESRCH) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to send SIGTERM to init pid %llu"),
|
|
|
|
(unsigned long long)priv->initpid);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-28 13:26:52 +00:00
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2012-11-28 13:26:52 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
static int
|
2012-11-23 10:36:47 +00:00
|
|
|
lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef,
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2012-11-22 15:41:41 +00:00
|
|
|
virDomainDiskDefPtr disk;
|
2012-11-23 10:36:47 +00:00
|
|
|
virDomainNetDefPtr net;
|
2012-11-27 13:58:56 +00:00
|
|
|
virDomainHostdevDefPtr hostdev;
|
2012-08-14 15:38:27 +00:00
|
|
|
|
|
|
|
switch (dev->type) {
|
2012-11-22 15:41:41 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_DISK:
|
|
|
|
disk = dev->data.disk;
|
|
|
|
if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("target %s already exists."), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-07-04 10:11:37 +00:00
|
|
|
if (virDomainDiskInsert(vmdef, disk))
|
2012-11-22 15:41:41 +00:00
|
|
|
return -1;
|
|
|
|
/* vmdef has the pointer. Generic codes for vmdef will do all jobs */
|
|
|
|
dev->data.disk = NULL;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2012-11-23 10:36:47 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_NET:
|
|
|
|
net = dev->data.net;
|
2013-07-04 10:11:37 +00:00
|
|
|
if (virDomainNetInsert(vmdef, net) < 0)
|
2012-11-23 10:36:47 +00:00
|
|
|
goto cleanup;
|
|
|
|
dev->data.net = NULL;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2012-11-27 13:58:56 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
|
|
|
hostdev = dev->data.hostdev;
|
|
|
|
if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("device is already in the domain configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-07-04 10:11:37 +00:00
|
|
|
if (virDomainHostdevInsert(vmdef, hostdev) < 0)
|
2012-11-27 13:58:56 +00:00
|
|
|
return -1;
|
|
|
|
dev->data.hostdev = NULL;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("persistent attach of device is not supported"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-08-14 15:38:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2012-11-23 10:36:47 +00:00
|
|
|
lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2012-11-23 10:36:47 +00:00
|
|
|
virDomainNetDefPtr net;
|
|
|
|
int idx;
|
2012-08-14 15:38:27 +00:00
|
|
|
|
|
|
|
switch (dev->type) {
|
2012-11-23 10:36:47 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_NET:
|
|
|
|
net = dev->data.net;
|
2014-04-01 13:56:55 +00:00
|
|
|
if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
|
2012-11-23 10:36:47 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virDomainNetDefFree(vmdef->nets[idx]);
|
|
|
|
|
|
|
|
vmdef->nets[idx] = net;
|
|
|
|
dev->data.net = NULL;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("persistent update of device is not supported"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-08-14 15:38:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2012-11-23 10:36:47 +00:00
|
|
|
lxcDomainDetachDeviceConfig(virDomainDefPtr vmdef,
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2012-11-22 15:41:41 +00:00
|
|
|
virDomainDiskDefPtr disk, det_disk;
|
2012-11-23 10:36:47 +00:00
|
|
|
virDomainNetDefPtr net;
|
2012-11-27 13:58:56 +00:00
|
|
|
virDomainHostdevDefPtr hostdev, det_hostdev;
|
2012-11-23 10:36:47 +00:00
|
|
|
int idx;
|
2012-08-14 15:38:27 +00:00
|
|
|
|
|
|
|
switch (dev->type) {
|
2012-11-22 15:41:41 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_DISK:
|
|
|
|
disk = dev->data.disk;
|
|
|
|
if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("no target device %s"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virDomainDiskDefFree(det_disk);
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2012-11-23 10:36:47 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_NET:
|
|
|
|
net = dev->data.net;
|
2014-04-01 13:56:55 +00:00
|
|
|
if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
|
2012-11-23 10:36:47 +00:00
|
|
|
goto cleanup;
|
2014-04-01 13:56:55 +00:00
|
|
|
|
2012-11-23 10:36:47 +00:00
|
|
|
/* this is guaranteed to succeed */
|
|
|
|
virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2012-11-27 13:58:56 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_HOSTDEV: {
|
|
|
|
hostdev = dev->data.hostdev;
|
|
|
|
if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("device not present in domain configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virDomainHostdevRemove(vmdef, idx);
|
|
|
|
virDomainHostdevDefFree(det_hostdev);
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("persistent detach of device is not supported"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-08-14 15:38:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-30 15:59:20 +00:00
|
|
|
struct lxcDomainAttachDeviceMknodData {
|
|
|
|
virLXCDriverPtr driver;
|
|
|
|
mode_t mode;
|
|
|
|
dev_t dev;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainDeviceDefPtr def;
|
|
|
|
char *file;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct lxcDomainAttachDeviceMknodData *data = opaque;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virSecurityManagerPostFork(data->driver->securityManager);
|
|
|
|
|
|
|
|
if (virFileMakeParentPath(data->file) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to create %s"), data->file);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Yes, the device name we're creating may not
|
|
|
|
* actually correspond to the major:minor number
|
|
|
|
* we're using, but we've no other option at this
|
|
|
|
* time. Just have to hope that containerized apps
|
|
|
|
* don't get upset that the major:minor is different
|
|
|
|
* to that normally implied by the device name
|
|
|
|
*/
|
|
|
|
VIR_DEBUG("Creating dev %s (%d,%d)",
|
|
|
|
data->file, major(data->dev), minor(data->dev));
|
|
|
|
if (mknod(data->file, data->mode, data->dev) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to create device %s"),
|
|
|
|
data->file);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lxcContainerChown(data->vm->def, data->file) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Labelling normally operates on src, but we need
|
|
|
|
* to actually label the dst here, so hack the config */
|
|
|
|
switch (data->def->type) {
|
|
|
|
case VIR_DOMAIN_DEVICE_DISK: {
|
|
|
|
virDomainDiskDefPtr def = data->def->data.disk;
|
2014-05-21 23:13:12 +00:00
|
|
|
char *tmpsrc = def->src->path;
|
|
|
|
def->src->path = data->file;
|
2014-06-18 12:46:27 +00:00
|
|
|
if (virSecurityManagerSetDiskLabel(data->driver->securityManager,
|
|
|
|
data->vm->def, def) < 0) {
|
2014-05-21 23:13:12 +00:00
|
|
|
def->src->path = tmpsrc;
|
2014-01-30 15:59:20 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-05-21 23:13:12 +00:00
|
|
|
def->src->path = tmpsrc;
|
2014-01-30 15:59:20 +00:00
|
|
|
} break;
|
|
|
|
|
2014-01-30 16:34:19 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_HOSTDEV: {
|
|
|
|
virDomainHostdevDefPtr def = data->def->data.hostdev;
|
|
|
|
if (virSecurityManagerSetHostdevLabel(data->driver->securityManager,
|
|
|
|
data->vm->def, def, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} break;
|
|
|
|
|
2014-01-30 15:59:20 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unexpected device type %d"),
|
|
|
|
data->def->type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (ret < 0)
|
|
|
|
unlink(data->file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceMknod(virLXCDriverPtr driver,
|
|
|
|
mode_t mode,
|
|
|
|
dev_t dev,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr def,
|
|
|
|
char *file)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
struct lxcDomainAttachDeviceMknodData data;
|
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
|
|
|
|
data.driver = driver;
|
|
|
|
data.mode = mode;
|
|
|
|
data.dev = dev;
|
|
|
|
data.vm = vm;
|
|
|
|
data.def = def;
|
|
|
|
data.file = file;
|
|
|
|
|
|
|
|
if (virSecurityManagerPreFork(driver->securityManager) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virProcessRunInMountNamespace(priv->initpid,
|
|
|
|
lxcDomainAttachDeviceMknodHelper,
|
|
|
|
&data) < 0) {
|
|
|
|
virSecurityManagerPostFork(driver->securityManager);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virSecurityManagerPostFork(driver->securityManager);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-30 17:58:36 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceUnlinkHelper(pid_t pid ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
const char *path = opaque;
|
|
|
|
|
|
|
|
VIR_DEBUG("Unlinking %s", path);
|
|
|
|
if (unlink(path) < 0 && errno != ENOENT) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to remove device %s"), path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceUnlink(virDomainObjPtr vm,
|
|
|
|
char *file)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
if (virProcessRunInMountNamespace(priv->initpid,
|
|
|
|
lxcDomainAttachDeviceUnlinkHelper,
|
|
|
|
file) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-22 16:16:06 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainDiskDefPtr def = dev->data.disk;
|
|
|
|
int ret = -1;
|
|
|
|
struct stat sb;
|
2014-01-30 15:59:20 +00:00
|
|
|
char *file = NULL;
|
|
|
|
int perms;
|
2014-03-17 20:49:05 +00:00
|
|
|
const char *src = NULL;
|
2012-11-22 16:16:06 +00:00
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach disk until init PID is known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-02-05 17:48:03 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("devices cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-07-18 11:34:34 +00:00
|
|
|
if (!virDomainDiskSourceIsBlockType(def->src, true))
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
2015-07-18 11:34:34 +00:00
|
|
|
|
2014-03-17 20:49:05 +00:00
|
|
|
src = virDomainDiskGetSource(def);
|
|
|
|
if (src == NULL) {
|
2012-11-22 16:16:06 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Can't setup disk without media"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainDiskIndexByName(vm->def, def->dst, true) >= 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), def->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-03-17 20:49:05 +00:00
|
|
|
if (stat(src, &sb) < 0) {
|
2012-11-22 16:16:06 +00:00
|
|
|
virReportSystemError(errno,
|
2014-03-17 20:49:05 +00:00
|
|
|
_("Unable to access %s"), src);
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-02-05 11:01:09 +00:00
|
|
|
if (!S_ISBLK(sb.st_mode)) {
|
2012-11-22 16:16:06 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2014-02-05 11:01:09 +00:00
|
|
|
_("Disk source %s must be a block device"),
|
2014-03-17 20:49:05 +00:00
|
|
|
src);
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:15:55 +00:00
|
|
|
perms = (def->src->readonly ?
|
2014-01-30 15:59:20 +00:00
|
|
|
VIR_CGROUP_DEVICE_READ :
|
|
|
|
VIR_CGROUP_DEVICE_RW) |
|
|
|
|
VIR_CGROUP_DEVICE_MKNOD;
|
2012-11-22 16:16:06 +00:00
|
|
|
|
2014-01-30 15:59:20 +00:00
|
|
|
if (virCgroupAllowDevice(priv->cgroup,
|
|
|
|
'b',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
perms) < 0)
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
2013-07-16 02:00:03 +00:00
|
|
|
|
2014-01-30 15:59:20 +00:00
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
|
2013-07-16 02:00:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 15:59:20 +00:00
|
|
|
if (virAsprintf(&file,
|
|
|
|
"/dev/%s", def->dst) < 0)
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 15:59:20 +00:00
|
|
|
if (lxcDomainAttachDeviceMknod(driver,
|
|
|
|
0700 | S_IFBLK,
|
|
|
|
sb.st_rdev,
|
|
|
|
vm,
|
|
|
|
dev,
|
|
|
|
file) < 0) {
|
|
|
|
if (virCgroupDenyDevice(priv->cgroup,
|
|
|
|
'b',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
perms) < 0)
|
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
2014-03-17 20:49:05 +00:00
|
|
|
src, vm->def->name);
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, def);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-03-17 20:49:05 +00:00
|
|
|
if (src)
|
2014-07-03 08:28:12 +00:00
|
|
|
virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
|
2014-01-30 15:59:20 +00:00
|
|
|
VIR_FREE(file);
|
2012-11-22 16:16:06 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-26 16:14:37 +00:00
|
|
|
/* XXX conn required for network -> bridge resolution */
|
2012-08-14 15:38:27 +00:00
|
|
|
static int
|
2012-11-26 16:14:37 +00:00
|
|
|
lxcDomainAttachDeviceNetLive(virConnectPtr conn,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainNetDefPtr net)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int ret = -1;
|
|
|
|
int actualType;
|
2015-01-07 14:52:21 +00:00
|
|
|
virNetDevBandwidthPtr actualBandwidth;
|
2012-11-26 16:14:37 +00:00
|
|
|
char *veth = NULL;
|
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach disk until init PID is known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* preallocate new slot for device */
|
2013-07-04 10:11:37 +00:00
|
|
|
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
|
2012-11-26 16:14:37 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* If appropriate, grab a physical device from the configured
|
|
|
|
* network's pool of devices, or resolve bridge device name
|
|
|
|
* to the one defined in the network definition.
|
|
|
|
*/
|
2014-01-31 15:48:06 +00:00
|
|
|
if (networkAllocateActualDevice(vm->def, net) < 0)
|
2012-11-26 16:14:37 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
actualType = virDomainNetGetActualType(net);
|
|
|
|
|
|
|
|
switch (actualType) {
|
2014-11-21 20:08:50 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK: {
|
2012-11-26 16:14:37 +00:00
|
|
|
const char *brname = virDomainNetGetActualBridgeName(net);
|
|
|
|
if (!brname) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No bridge name specified"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-11-07 10:37:37 +00:00
|
|
|
if (!(veth = virLXCProcessSetupInterfaceBridged(vm->def,
|
2012-11-26 16:14:37 +00:00
|
|
|
net,
|
|
|
|
brname)))
|
|
|
|
goto cleanup;
|
|
|
|
} break;
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT: {
|
|
|
|
if (!(veth = virLXCProcessSetupInterfaceDirect(conn,
|
|
|
|
vm->def,
|
|
|
|
net)))
|
|
|
|
goto cleanup;
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Network device type is not supported"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-01-07 14:52:21 +00:00
|
|
|
/* Set bandwidth or warn if requested and not supported. */
|
|
|
|
actualBandwidth = virDomainNetGetActualBandwidth(net);
|
|
|
|
if (actualBandwidth) {
|
|
|
|
if (virNetDevSupportBandwidth(actualType)) {
|
|
|
|
if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
VIR_WARN("setting bandwidth on interfaces of "
|
|
|
|
"type '%s' is not implemented yet",
|
|
|
|
virDomainNetTypeToString(actualType));
|
|
|
|
}
|
|
|
|
}
|
2012-11-26 16:14:37 +00:00
|
|
|
|
|
|
|
if (virNetDevSetNamespace(veth, priv->initpid) < 0) {
|
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", true);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-26 16:14:37 +00:00
|
|
|
if (!ret) {
|
|
|
|
vm->def->nets[vm->def->nnets++] = net;
|
|
|
|
} else if (veth) {
|
|
|
|
switch (actualType) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
ignore_value(virNetDevVethDelete(veth));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
ignore_value(virNetDevMacVLanDelete(veth));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainHostdevDefPtr def = dev->data.hostdev;
|
|
|
|
int ret = -1;
|
|
|
|
char *src = NULL;
|
|
|
|
struct stat sb;
|
2013-01-14 22:11:44 +00:00
|
|
|
virUSBDevicePtr usb = NULL;
|
2014-07-03 19:43:05 +00:00
|
|
|
virDomainHostdevSubsysUSBPtr usbsrc;
|
2012-11-27 16:19:43 +00:00
|
|
|
|
|
|
|
if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("host USB device already exists"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
usbsrc = &def->source.subsys.u.usb;
|
2012-11-27 16:19:43 +00:00
|
|
|
if (virAsprintf(&src, "/dev/bus/usb/%03d/%03d",
|
2014-07-03 19:43:05 +00:00
|
|
|
usbsrc->bus, usbsrc->device) < 0)
|
2012-11-27 16:19:43 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
|
2012-11-27 16:19:43 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (stat(src, &sb) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to access %s"), src);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISCHR(sb.st_mode)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("USB source %s was not a character device"),
|
|
|
|
src);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-02-04 16:46:28 +00:00
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virUSBDeviceFileIterate(usb,
|
2014-03-13 11:58:17 +00:00
|
|
|
virLXCSetupHostUSBDeviceCgroup,
|
2014-02-04 16:43:18 +00:00
|
|
|
priv->cgroup) < 0)
|
2012-11-27 16:19:43 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 16:34:19 +00:00
|
|
|
if (lxcDomainAttachDeviceMknod(driver,
|
|
|
|
0700 | S_IFCHR,
|
|
|
|
sb.st_rdev,
|
|
|
|
vm,
|
|
|
|
dev,
|
|
|
|
src) < 0) {
|
|
|
|
if (virUSBDeviceFileIterate(usb,
|
2014-03-13 11:58:17 +00:00
|
|
|
virLXCTeardownHostUSBDeviceCgroup,
|
2014-01-30 16:34:19 +00:00
|
|
|
priv->cgroup) < 0)
|
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
|
|
|
src, vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-02-04 16:46:28 +00:00
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = def;
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-27 16:19:43 +00:00
|
|
|
virDomainAuditHostdev(vm, def, "attach", ret == 0);
|
2013-01-14 22:11:44 +00:00
|
|
|
virUSBDeviceFree(usb);
|
2012-11-27 16:19:43 +00:00
|
|
|
VIR_FREE(src);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainHostdevDefPtr def = dev->data.hostdev;
|
|
|
|
int ret = -1;
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
if (!def->source.caps.u.storage.block) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Missing storage block path"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("host device already exists"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(def->source.caps.u.storage.block, &sb) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to access %s"),
|
|
|
|
def->source.caps.u.storage.block);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISBLK(sb.st_mode)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Hostdev source %s must be a block device"),
|
|
|
|
def->source.caps.u.storage.block);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-04 10:11:37 +00:00
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
|
2012-11-28 16:48:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 17:45:08 +00:00
|
|
|
if (virCgroupAllowDevice(priv->cgroup,
|
|
|
|
'b',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
VIR_CGROUP_DEVICE_RWM) < 0)
|
2012-11-28 16:48:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 17:45:08 +00:00
|
|
|
if (lxcDomainAttachDeviceMknod(driver,
|
|
|
|
0700 | S_IFBLK,
|
|
|
|
sb.st_rdev,
|
|
|
|
vm,
|
|
|
|
dev,
|
|
|
|
def->source.caps.u.storage.block) < 0) {
|
|
|
|
if (virCgroupDenyDevice(priv->cgroup,
|
|
|
|
'b',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
VIR_CGROUP_DEVICE_RWM) < 0)
|
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
|
|
|
def->source.caps.u.storage.block, vm->def->name);
|
2012-11-28 16:48:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = def;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-28 16:48:18 +00:00
|
|
|
virDomainAuditHostdev(vm, def, "attach", ret == 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 18:31:14 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainHostdevDefPtr def = dev->data.hostdev;
|
|
|
|
int ret = -1;
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
if (!def->source.caps.u.misc.chardev) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Missing storage block path"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("host device already exists"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(def->source.caps.u.misc.chardev, &sb) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to access %s"),
|
|
|
|
def->source.caps.u.misc.chardev);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISCHR(sb.st_mode)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Hostdev source %s must be a block device"),
|
|
|
|
def->source.caps.u.misc.chardev);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-01-30 17:47:39 +00:00
|
|
|
if (virCgroupAllowDevice(priv->cgroup,
|
|
|
|
'c',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
VIR_CGROUP_DEVICE_RWM) < 0)
|
2012-11-28 18:31:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:11:37 +00:00
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
|
2012-11-28 18:31:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 17:47:39 +00:00
|
|
|
if (lxcDomainAttachDeviceMknod(driver,
|
|
|
|
0700 | S_IFBLK,
|
|
|
|
sb.st_rdev,
|
|
|
|
vm,
|
|
|
|
dev,
|
|
|
|
def->source.caps.u.misc.chardev) < 0) {
|
|
|
|
if (virCgroupDenyDevice(priv->cgroup,
|
|
|
|
'c',
|
|
|
|
major(sb.st_rdev),
|
|
|
|
minor(sb.st_rdev),
|
|
|
|
VIR_CGROUP_DEVICE_RWM) < 0)
|
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
|
|
|
def->source.caps.u.storage.block, vm->def->name);
|
2012-11-28 18:31:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = def;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-28 18:31:14 +00:00
|
|
|
virDomainAuditHostdev(vm, def, "attach", ret == 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
switch (dev->data.hostdev->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
|
|
return lxcDomainAttachDeviceHostdevSubsysUSBLive(driver, vm, dev);
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported host device type %s"),
|
|
|
|
virDomainHostdevSubsysTypeToString(dev->data.hostdev->source.subsys.type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceHostdevCapsLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
switch (dev->data.hostdev->source.caps.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
|
|
|
|
return lxcDomainAttachDeviceHostdevStorageLive(driver, vm, dev);
|
|
|
|
|
2012-11-28 18:31:14 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
|
|
|
|
return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported host device type %s"),
|
|
|
|
virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach hostdev until init PID is known"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-05 17:48:03 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("devices cgroup isn't mounted"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
switch (dev->data.hostdev->mode) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
|
|
|
|
return lxcDomainAttachDeviceHostdevSubsysLive(driver, vm, dev);
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
|
|
|
return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported host device mode %s"),
|
|
|
|
virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-26 16:14:37 +00:00
|
|
|
static int
|
|
|
|
lxcDomainAttachDeviceLive(virConnectPtr conn,
|
|
|
|
virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
switch (dev->type) {
|
2012-11-22 16:16:06 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_DISK:
|
|
|
|
ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
|
|
|
|
if (!ret)
|
|
|
|
dev->data.disk = NULL;
|
|
|
|
break;
|
|
|
|
|
2012-11-26 16:14:37 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_NET:
|
|
|
|
ret = lxcDomainAttachDeviceNetLive(conn, vm,
|
|
|
|
dev->data.net);
|
|
|
|
if (!ret)
|
|
|
|
dev->data.net = NULL;
|
|
|
|
break;
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
|
|
|
ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
|
|
|
|
if (!ret)
|
|
|
|
dev->data.disk = NULL;
|
|
|
|
break;
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("device type '%s' cannot be attached"),
|
|
|
|
virDomainDeviceTypeToString(dev->type));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-22 16:16:06 +00:00
|
|
|
static int
|
2013-03-21 14:40:29 +00:00
|
|
|
lxcDomainDetachDeviceDiskLive(virDomainObjPtr vm,
|
2012-11-22 16:16:06 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainDiskDefPtr def = NULL;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int idx, ret = -1;
|
2013-01-22 14:15:44 +00:00
|
|
|
char *dst = NULL;
|
2014-03-17 20:49:05 +00:00
|
|
|
const char *src;
|
2012-11-22 16:16:06 +00:00
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach disk until init PID is known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if ((idx = virDomainDiskIndexByName(vm->def,
|
|
|
|
dev->data.disk->dst,
|
|
|
|
false)) < 0) {
|
2012-11-22 16:16:06 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk %s not found"), dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
def = vm->def->disks[idx];
|
2014-03-17 20:49:05 +00:00
|
|
|
src = virDomainDiskGetSource(def);
|
2012-11-22 16:16:06 +00:00
|
|
|
|
2014-01-30 17:58:36 +00:00
|
|
|
if (virAsprintf(&dst, "/dev/%s", def->dst) < 0)
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
2012-11-22 16:16:06 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("devices cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-01-30 17:58:36 +00:00
|
|
|
if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
|
2014-07-03 08:28:12 +00:00
|
|
|
virDomainAuditDisk(vm, def->src, NULL, "detach", false);
|
2012-11-22 16:16:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-07-03 08:28:12 +00:00
|
|
|
virDomainAuditDisk(vm, def->src, NULL, "detach", true);
|
2012-11-22 16:16:06 +00:00
|
|
|
|
2014-03-17 20:49:05 +00:00
|
|
|
if (virCgroupDenyDevicePath(priv->cgroup, src, VIR_CGROUP_DEVICE_RWM) != 0)
|
2012-11-22 16:16:06 +00:00
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
2014-03-17 20:49:05 +00:00
|
|
|
src, vm->def->name);
|
2012-11-22 16:16:06 +00:00
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
virDomainDiskRemove(vm->def, idx);
|
2012-11-22 16:16:06 +00:00
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-22 16:16:06 +00:00
|
|
|
VIR_FREE(dst);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
static int
|
2012-11-26 16:14:37 +00:00
|
|
|
lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
2014-11-18 23:55:48 +00:00
|
|
|
int detachidx, actualType, ret = -1;
|
2012-11-26 16:14:37 +00:00
|
|
|
virDomainNetDefPtr detach = NULL;
|
|
|
|
virNetDevVPortProfilePtr vport = NULL;
|
|
|
|
|
2014-04-01 13:56:55 +00:00
|
|
|
if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
|
2012-11-26 16:14:37 +00:00
|
|
|
goto cleanup;
|
2014-04-01 13:56:55 +00:00
|
|
|
|
2012-11-26 16:14:37 +00:00
|
|
|
detach = vm->def->nets[detachidx];
|
2014-11-18 23:55:48 +00:00
|
|
|
actualType = virDomainNetGetActualType(detach);
|
|
|
|
|
|
|
|
/* clear network bandwidth */
|
2015-02-24 17:12:56 +00:00
|
|
|
if (virDomainNetGetActualBandwidth(detach) &&
|
|
|
|
virNetDevSupportBandwidth(actualType) &&
|
2014-11-18 23:55:48 +00:00
|
|
|
virNetDevBandwidthClear(detach->ifname))
|
|
|
|
goto cleanup;
|
2012-11-26 16:14:37 +00:00
|
|
|
|
2014-11-18 23:55:48 +00:00
|
|
|
switch (actualType) {
|
2012-11-26 16:14:37 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
if (virNetDevVethDelete(detach->ifname) < 0) {
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* It'd be nice to support this, but with macvlan
|
|
|
|
* once assigned to a container nothing exists on
|
|
|
|
* the host side. Further the container can change
|
|
|
|
* the mac address of NIC name, so we can't easily
|
|
|
|
* find out which guest NIC it maps to
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
*/
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Only bridged veth devices can be detached"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", true);
|
|
|
|
|
|
|
|
virDomainConfNWFilterTeardown(detach);
|
|
|
|
|
|
|
|
vport = virDomainNetGetActualVirtPortProfile(detach);
|
|
|
|
if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
|
|
|
|
ignore_value(virNetDevOpenvswitchRemovePort(
|
|
|
|
virDomainNetGetActualBridgeName(detach),
|
|
|
|
detach->ifname));
|
|
|
|
ret = 0;
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-26 16:14:37 +00:00
|
|
|
if (!ret) {
|
2014-01-31 15:48:06 +00:00
|
|
|
networkReleaseActualDevice(vm->def, detach);
|
2012-11-26 16:14:37 +00:00
|
|
|
virDomainNetRemove(vm->def, detachidx);
|
|
|
|
virDomainNetDefFree(detach);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainHostdevDefPtr def = NULL;
|
|
|
|
int idx, ret = -1;
|
2013-01-22 14:15:44 +00:00
|
|
|
char *dst = NULL;
|
2013-01-14 22:11:44 +00:00
|
|
|
virUSBDevicePtr usb = NULL;
|
2014-03-05 10:49:58 +00:00
|
|
|
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
|
2014-07-03 19:43:05 +00:00
|
|
|
virDomainHostdevSubsysUSBPtr usbsrc;
|
2012-11-27 16:19:43 +00:00
|
|
|
|
|
|
|
if ((idx = virDomainHostdevFind(vm->def,
|
|
|
|
dev->data.hostdev,
|
|
|
|
&def)) < 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("usb device not found"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
usbsrc = &def->source.subsys.u.usb;
|
2014-01-30 17:58:36 +00:00
|
|
|
if (virAsprintf(&dst, "/dev/bus/usb/%03d/%03d",
|
2014-07-03 19:43:05 +00:00
|
|
|
usbsrc->bus, usbsrc->device) < 0)
|
2012-11-27 16:19:43 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
2012-11-27 16:19:43 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("devices cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
|
2012-11-27 16:19:43 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-30 17:58:36 +00:00
|
|
|
if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
|
2012-11-27 16:19:43 +00:00
|
|
|
virDomainAuditHostdev(vm, def, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virDomainAuditHostdev(vm, def, "detach", true);
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virUSBDeviceFileIterate(usb,
|
2014-03-13 11:58:17 +00:00
|
|
|
virLXCTeardownHostUSBDeviceCgroup,
|
2014-02-04 17:41:22 +00:00
|
|
|
priv->cgroup) < 0)
|
2012-11-27 16:19:43 +00:00
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
|
|
|
dst, vm->def->name);
|
|
|
|
|
2014-03-12 16:38:18 +00:00
|
|
|
virObjectLock(hostdev_mgr->activeUSBHostdevs);
|
|
|
|
virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
|
|
|
|
virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
|
2012-11-27 16:19:43 +00:00
|
|
|
|
|
|
|
virDomainHostdevRemove(vm->def, idx);
|
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-01-14 22:11:44 +00:00
|
|
|
virUSBDeviceFree(usb);
|
2012-11-27 16:19:43 +00:00
|
|
|
VIR_FREE(dst);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
|
|
|
|
static int
|
2013-03-21 14:40:29 +00:00
|
|
|
lxcDomainDetachDeviceHostdevStorageLive(virDomainObjPtr vm,
|
2012-11-28 16:48:18 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainHostdevDefPtr def = NULL;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int idx, ret = -1;
|
2012-11-28 16:48:18 +00:00
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach disk until init PID is known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if ((idx = virDomainHostdevFind(vm->def,
|
|
|
|
dev->data.hostdev,
|
|
|
|
&def)) < 0) {
|
2012-11-28 16:48:18 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("hostdev %s not found"),
|
|
|
|
dev->data.hostdev->source.caps.u.storage.block);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
2012-11-28 16:48:18 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("devices cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-01-30 17:58:36 +00:00
|
|
|
if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
|
2012-11-28 16:48:18 +00:00
|
|
|
virDomainAuditHostdev(vm, def, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virDomainAuditHostdev(vm, def, "detach", true);
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block, VIR_CGROUP_DEVICE_RWM) != 0)
|
2012-11-28 16:48:18 +00:00
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
|
|
|
def->source.caps.u.storage.block, vm->def->name);
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
virDomainHostdevRemove(vm->def, idx);
|
2012-11-28 16:48:18 +00:00
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-28 16:48:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 18:31:14 +00:00
|
|
|
static int
|
2013-03-21 14:40:29 +00:00
|
|
|
lxcDomainDetachDeviceHostdevMiscLive(virDomainObjPtr vm,
|
2012-11-28 18:31:14 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainHostdevDefPtr def = NULL;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int idx, ret = -1;
|
2012-11-28 18:31:14 +00:00
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach disk until init PID is known"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if ((idx = virDomainHostdevFind(vm->def,
|
|
|
|
dev->data.hostdev,
|
|
|
|
&def)) < 0) {
|
2012-11-28 18:31:14 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("hostdev %s not found"),
|
|
|
|
dev->data.hostdev->source.caps.u.misc.chardev);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
2012-11-28 18:31:14 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("devices cgroup isn't mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-01-30 17:58:36 +00:00
|
|
|
if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
|
2012-11-28 18:31:14 +00:00
|
|
|
virDomainAuditHostdev(vm, def, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virDomainAuditHostdev(vm, def, "detach", true);
|
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev, VIR_CGROUP_DEVICE_RWM) != 0)
|
2012-11-28 18:31:14 +00:00
|
|
|
VIR_WARN("cannot deny device %s for domain %s",
|
|
|
|
def->source.caps.u.misc.chardev, vm->def->name);
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
virDomainHostdevRemove(vm->def, idx);
|
2012-11-28 18:31:14 +00:00
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-11-28 18:31:14 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
switch (dev->data.hostdev->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
|
|
return lxcDomainDetachDeviceHostdevUSBLive(driver, vm, dev);
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported host device type %s"),
|
|
|
|
virDomainHostdevSubsysTypeToString(dev->data.hostdev->source.subsys.type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
static int
|
2013-03-21 14:40:29 +00:00
|
|
|
lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
2012-11-28 16:48:18 +00:00
|
|
|
{
|
|
|
|
switch (dev->data.hostdev->source.caps.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
|
2013-03-21 14:40:29 +00:00
|
|
|
return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
|
2012-11-28 16:48:18 +00:00
|
|
|
|
2012-11-28 18:31:14 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
|
2013-03-21 14:40:29 +00:00
|
|
|
return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
|
2012-11-28 18:31:14 +00:00
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported host device type %s"),
|
|
|
|
virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
static int
|
|
|
|
lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virLXCDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Cannot attach hostdev until init PID is known"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (dev->data.hostdev->mode) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
|
|
|
|
return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev);
|
|
|
|
|
2012-11-28 16:48:18 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
2013-03-21 14:40:29 +00:00
|
|
|
return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
|
2012-11-28 16:48:18 +00:00
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported host device mode %s"),
|
|
|
|
virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-26 16:14:37 +00:00
|
|
|
static int
|
|
|
|
lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
switch (dev->type) {
|
2012-11-22 16:16:06 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_DISK:
|
2013-03-21 14:40:29 +00:00
|
|
|
ret = lxcDomainDetachDeviceDiskLive(vm, dev);
|
2012-11-22 16:16:06 +00:00
|
|
|
break;
|
|
|
|
|
2012-11-26 16:14:37 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_NET:
|
|
|
|
ret = lxcDomainDetachDeviceNetLive(vm, dev);
|
|
|
|
break;
|
|
|
|
|
2012-11-27 16:19:43 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
|
|
|
ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
|
|
|
|
break;
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("device type '%s' cannot be detached"),
|
|
|
|
virDomainDeviceTypeToString(dev->type));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
|
|
|
|
const char *xml,
|
|
|
|
unsigned int flags)
|
2012-08-14 15:38:27 +00:00
|
|
|
{
|
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
virDomainDefPtr vmdef = NULL;
|
|
|
|
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned int affect;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2012-08-14 15:38:27 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
2013-04-29 15:59:42 +00:00
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
2012-08-14 15:38:27 +00:00
|
|
|
|
|
|
|
affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2012-08-14 15:38:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
if (virDomainObjIsActive(vm)) {
|
|
|
|
if (affect == VIR_DOMAIN_AFFECT_CURRENT)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
} else {
|
|
|
|
if (affect == VIR_DOMAIN_AFFECT_CURRENT)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
/* check consistency between flags and the vm state */
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot do live update a device on "
|
|
|
|
"inactive domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-08-14 15:38:27 +00:00
|
|
|
if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot modify device on transient domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-03-28 13:55:55 +00:00
|
|
|
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps, driver->xmlopt,
|
2014-11-18 16:44:00 +00:00
|
|
|
VIR_DOMAIN_DEF_PARSE_INACTIVE);
|
2012-08-14 15:38:27 +00:00
|
|
|
if (dev == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
|
|
|
|
flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
/* If we are affecting both CONFIG and LIVE
|
|
|
|
* create a deep copy of device as adding
|
|
|
|
* to CONFIG takes one instance.
|
|
|
|
*/
|
2013-03-28 13:55:55 +00:00
|
|
|
dev_copy = virDomainDeviceDefCopy(dev, vm->def,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps, driver->xmlopt);
|
2012-08-14 15:38:27 +00:00
|
|
|
if (!dev_copy)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
/* Make a copy for updated domain. */
|
2013-07-15 09:43:10 +00:00
|
|
|
vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
|
2012-08-14 15:38:27 +00:00
|
|
|
if (!vmdef)
|
|
|
|
goto cleanup;
|
2014-03-20 12:04:06 +00:00
|
|
|
|
2014-03-20 12:39:20 +00:00
|
|
|
if (virDomainDefCompatibleDevice(vmdef, dev,
|
|
|
|
VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
|
2014-03-20 12:04:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
|
2012-08-14 15:38:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2014-03-20 12:39:20 +00:00
|
|
|
if (virDomainDefCompatibleDevice(vm->def, dev_copy,
|
|
|
|
VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
|
2012-08-14 15:38:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
if ((ret = lxcDomainAttachDeviceLive(dom->conn, driver, vm, dev_copy)) < 0)
|
2012-08-14 15:38:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
/*
|
|
|
|
* update domain status forcibly because the domain status may be
|
|
|
|
* changed even if we failed to attach the device. For example,
|
|
|
|
* a new controller may be created.
|
|
|
|
*/
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
|
2012-08-14 15:38:27 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, if no error until here, we can save config. */
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2013-07-16 15:45:05 +00:00
|
|
|
ret = virDomainSaveConfig(cfg->configDir, vmdef);
|
2012-08-14 15:38:27 +00:00
|
|
|
if (!ret) {
|
Merge virDomainObjListIsDuplicate into virDomainObjListAdd
The duplicate VM checking should be done atomically with
virDomainObjListAdd, so shoud not be a separate function.
Instead just use flags to indicate what kind of checks are
required.
This pair, used in virDomainCreateXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainRestoreFlags:
if (virDomainObjListIsDuplicate(privconn->domains, def, 1) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, true)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
This pair, used in virDomainDefineXML:
if (virDomainObjListIsDuplicate(privconn->domains, def, 0) < 0)
goto cleanup;
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def, false)))
goto cleanup;
Changes to
if (!(dom = virDomainObjListAdd(privconn->domains,
privconn->caps,
def,
0, NULL)))
goto cleanup;
2013-01-14 14:46:58 +00:00
|
|
|
virDomainObjAssignDef(vm, vmdef, false, NULL);
|
2012-08-14 15:38:27 +00:00
|
|
|
vmdef = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2012-08-14 15:38:27 +00:00
|
|
|
virDomainDefFree(vmdef);
|
|
|
|
if (dev != dev_copy)
|
|
|
|
virDomainDeviceDefFree(dev_copy);
|
|
|
|
virDomainDeviceDefFree(dev);
|
|
|
|
if (vm)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2012-08-14 15:38:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcDomainAttachDevice(virDomainPtr dom,
|
|
|
|
const char *xml)
|
|
|
|
{
|
|
|
|
return lxcDomainAttachDeviceFlags(dom, xml,
|
|
|
|
VIR_DOMAIN_AFFECT_LIVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcDomainUpdateDeviceFlags(virDomainPtr dom,
|
|
|
|
const char *xml,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-29 15:59:42 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2013-04-29 15:59:42 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
virDomainDefPtr vmdef = NULL;
|
|
|
|
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned int affect;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-04-29 15:59:42 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
|
|
VIR_DOMAIN_DEVICE_MODIFY_FORCE, -1);
|
|
|
|
|
|
|
|
affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2013-04-29 15:59:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
if (virDomainObjIsActive(vm)) {
|
|
|
|
if (affect == VIR_DOMAIN_AFFECT_CURRENT)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
} else {
|
|
|
|
if (affect == VIR_DOMAIN_AFFECT_CURRENT)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
/* check consistency between flags and the vm state */
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot do live update a device on "
|
|
|
|
"inactive domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot modify device on transient domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps, driver->xmlopt,
|
2014-11-18 16:44:00 +00:00
|
|
|
VIR_DOMAIN_DEF_PARSE_INACTIVE);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (dev == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
|
|
|
|
flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
/* If we are affecting both CONFIG and LIVE
|
|
|
|
* create a deep copy of device as adding
|
|
|
|
* to CONFIG takes one instance.
|
|
|
|
*/
|
|
|
|
dev_copy = virDomainDeviceDefCopy(dev, vm->def,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps, driver->xmlopt);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (!dev_copy)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
/* Make a copy for updated domain. */
|
2013-07-15 09:43:10 +00:00
|
|
|
vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (!vmdef)
|
|
|
|
goto cleanup;
|
2014-03-20 12:04:06 +00:00
|
|
|
|
2014-03-20 12:39:20 +00:00
|
|
|
if (virDomainDefCompatibleDevice(vmdef, dev,
|
|
|
|
VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
|
2014-03-20 12:04:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
if ((ret = lxcDomainUpdateDeviceConfig(vmdef, dev)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2014-03-20 12:39:20 +00:00
|
|
|
if (virDomainDefCompatibleDevice(vm->def, dev_copy,
|
|
|
|
VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
|
2013-04-29 15:59:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
|
|
|
_("Unable to modify live devices"));
|
|
|
|
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, if no error until here, we can save config. */
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2013-07-16 15:45:05 +00:00
|
|
|
ret = virDomainSaveConfig(cfg->configDir, vmdef);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (!ret) {
|
|
|
|
virDomainObjAssignDef(vm, vmdef, false, NULL);
|
|
|
|
vmdef = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-04-29 15:59:42 +00:00
|
|
|
virDomainDefFree(vmdef);
|
|
|
|
if (dev != dev_copy)
|
|
|
|
virDomainDeviceDefFree(dev_copy);
|
|
|
|
virDomainDeviceDefFree(dev);
|
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2013-04-29 15:59:42 +00:00
|
|
|
return ret;
|
2012-08-14 15:38:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
|
|
|
|
const char *xml,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-29 15:59:42 +00:00
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
2013-07-15 09:43:10 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2013-04-29 15:59:42 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
virDomainDefPtr vmdef = NULL;
|
|
|
|
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
unsigned int affect;
|
2013-07-17 07:20:26 +00:00
|
|
|
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
|
2013-04-29 15:59:42 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
|
|
|
|
affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2013-04-29 15:59:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
if (virDomainObjIsActive(vm)) {
|
|
|
|
if (affect == VIR_DOMAIN_AFFECT_CURRENT)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
} else {
|
|
|
|
if (affect == VIR_DOMAIN_AFFECT_CURRENT)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
/* check consistency between flags and the vm state */
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot do live update a device on "
|
|
|
|
"inactive domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot modify device on transient domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:43:10 +00:00
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps, driver->xmlopt,
|
2014-11-18 16:44:00 +00:00
|
|
|
VIR_DOMAIN_DEF_PARSE_INACTIVE);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (dev == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
|
|
|
|
flags & VIR_DOMAIN_AFFECT_LIVE) {
|
|
|
|
/* If we are affecting both CONFIG and LIVE
|
|
|
|
* create a deep copy of device as adding
|
|
|
|
* to CONFIG takes one instance.
|
|
|
|
*/
|
|
|
|
dev_copy = virDomainDeviceDefCopy(dev, vm->def,
|
2013-07-15 09:43:10 +00:00
|
|
|
caps, driver->xmlopt);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (!dev_copy)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
|
|
|
/* Make a copy for updated domain. */
|
2013-07-15 09:43:10 +00:00
|
|
|
vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (!vmdef)
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-03-20 12:39:20 +00:00
|
|
|
if (virDomainDefCompatibleDevice(vmdef, dev,
|
|
|
|
VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
|
2014-03-20 12:04:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-29 15:59:42 +00:00
|
|
|
if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2014-03-20 12:39:20 +00:00
|
|
|
if (virDomainDefCompatibleDevice(vm->def, dev_copy,
|
|
|
|
VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
|
2013-04-29 15:59:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
/*
|
|
|
|
* update domain status forcibly because the domain status may be
|
|
|
|
* changed even if we failed to attach the device. For example,
|
|
|
|
* a new controller may be created.
|
|
|
|
*/
|
2013-07-16 15:45:05 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
|
2013-04-29 15:59:42 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, if no error until here, we can save config. */
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
|
2013-07-16 15:45:05 +00:00
|
|
|
ret = virDomainSaveConfig(cfg->configDir, vmdef);
|
2013-04-29 15:59:42 +00:00
|
|
|
if (!ret) {
|
|
|
|
virDomainObjAssignDef(vm, vmdef, false, NULL);
|
|
|
|
vmdef = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-04-29 15:59:42 +00:00
|
|
|
virDomainDefFree(vmdef);
|
|
|
|
if (dev != dev_copy)
|
|
|
|
virDomainDeviceDefFree(dev_copy);
|
|
|
|
virDomainDeviceDefFree(dev);
|
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
2013-07-15 09:43:10 +00:00
|
|
|
virObjectUnref(caps);
|
2013-07-16 15:45:05 +00:00
|
|
|
virObjectUnref(cfg);
|
2013-04-29 15:59:42 +00:00
|
|
|
return ret;
|
2012-08-14 15:38:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcDomainDetachDevice(virDomainPtr dom,
|
|
|
|
const char *xml)
|
|
|
|
{
|
|
|
|
return lxcDomainDetachDeviceFlags(dom, xml,
|
|
|
|
VIR_DOMAIN_AFFECT_LIVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
|
|
|
|
int **fdlist,
|
|
|
|
unsigned int flags)
|
2012-12-21 14:22:31 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
int ret = -1;
|
|
|
|
size_t nfds = 0;
|
|
|
|
|
|
|
|
*fdlist = NULL;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2013-07-17 07:37:09 +00:00
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
2012-12-21 14:22:31 +00:00
|
|
|
goto cleanup;
|
2013-07-17 07:37:09 +00:00
|
|
|
|
2012-12-21 14:22:31 +00:00
|
|
|
priv = vm->privateData;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-12-21 14:22:31 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("Domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!priv->initpid) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Init pid is not yet available"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = nfds;
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-01-22 22:09:25 +00:00
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
2012-12-21 14:22:31 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-03 17:55:20 +00:00
|
|
|
static char *
|
2013-04-23 12:50:18 +00:00
|
|
|
lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
|
2013-04-03 17:55:20 +00:00
|
|
|
{
|
|
|
|
virLXCDriverPtr driver = conn->privateData;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virConnectGetSysinfoEnsureACL(conn) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2013-04-03 17:55:20 +00:00
|
|
|
if (!driver->hostsysinfo) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Host SMBIOS information is not available"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
|
|
|
|
return NULL;
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-04-03 17:55:20 +00:00
|
|
|
return NULL;
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-26 17:21:58 +00:00
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetInfo(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
virNodeInfoPtr nodeinfo)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetInfoEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-07-07 11:27:53 +00:00
|
|
|
return nodeGetInfo(NULL, nodeinfo);
|
2013-04-26 17:21:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-14 17:49:00 +00:00
|
|
|
static int
|
|
|
|
lxcDomainMemoryStats(virDomainPtr dom,
|
2014-09-16 13:19:47 +00:00
|
|
|
virDomainMemoryStatPtr stats,
|
2014-02-14 17:49:00 +00:00
|
|
|
unsigned int nr_stats,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
unsigned long long swap_usage;
|
|
|
|
unsigned long mem_usage;
|
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
|
|
|
if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-02-20 15:32:49 +00:00
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("domain is not active"));
|
2014-02-14 17:49:00 +00:00
|
|
|
goto cleanup;
|
2014-02-20 15:32:49 +00:00
|
|
|
}
|
2014-02-14 17:49:00 +00:00
|
|
|
|
2014-02-20 15:32:49 +00:00
|
|
|
if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
|
2014-02-14 17:49:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-02-20 15:32:49 +00:00
|
|
|
if (virCgroupGetMemoryUsage(priv->cgroup, &mem_usage) < 0)
|
2014-02-14 17:49:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
if (ret < nr_stats) {
|
|
|
|
stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
|
|
|
|
stats[ret].val = vm->def->mem.cur_balloon;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
if (ret < nr_stats) {
|
|
|
|
stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_IN;
|
|
|
|
stats[ret].val = swap_usage;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
if (ret < nr_stats) {
|
|
|
|
stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
|
|
|
|
stats[ret].val = mem_usage;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-02-14 17:49:00 +00:00
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-26 17:21:58 +00:00
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetCPUStats(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
int cpuNum,
|
|
|
|
virNodeCPUStatsPtr params,
|
|
|
|
int *nparams,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetCPUStatsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-26 17:21:58 +00:00
|
|
|
return nodeGetCPUStats(cpuNum, params, nparams, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetMemoryStats(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
int cellNum,
|
|
|
|
virNodeMemoryStatsPtr params,
|
|
|
|
int *nparams,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-07-07 21:37:36 +00:00
|
|
|
return nodeGetMemoryStats(NULL, cellNum, params, nparams, flags);
|
2013-04-26 17:21:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetCellsFreeMemory(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
unsigned long long *freeMems,
|
|
|
|
int startCell,
|
|
|
|
int maxCells)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-26 17:21:58 +00:00
|
|
|
return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned long long
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetFreeMemory(virConnectPtr conn)
|
2013-04-26 17:21:58 +00:00
|
|
|
{
|
2014-06-16 12:02:34 +00:00
|
|
|
unsigned long long freeMem;
|
|
|
|
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
|
|
|
|
return 0;
|
|
|
|
|
2014-06-16 12:02:34 +00:00
|
|
|
if (nodeGetMemory(NULL, &freeMem) < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return freeMem;
|
2013-04-26 17:21:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetMemoryParameters(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
virTypedParameterPtr params,
|
|
|
|
int *nparams,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-26 17:21:58 +00:00
|
|
|
return nodeGetMemoryParameters(params, nparams, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeSetMemoryParameters(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-26 17:21:58 +00:00
|
|
|
return nodeSetMemoryParameters(params, nparams, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeGetCPUMap(virConnectPtr conn,
|
2013-04-26 17:21:58 +00:00
|
|
|
unsigned char **cpumap,
|
|
|
|
unsigned int *online,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeGetCPUMapEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-07-06 21:49:04 +00:00
|
|
|
return nodeGetCPUMap(NULL, cpumap, online, flags);
|
2013-04-26 17:21:58 +00:00
|
|
|
}
|
|
|
|
|
2013-04-29 09:16:56 +00:00
|
|
|
|
|
|
|
static int
|
2013-04-23 10:56:22 +00:00
|
|
|
lxcNodeSuspendForDuration(virConnectPtr conn,
|
2013-04-29 09:16:56 +00:00
|
|
|
unsigned int target,
|
|
|
|
unsigned long long duration,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-04-23 10:56:22 +00:00
|
|
|
if (virNodeSuspendForDurationEnsureACL(conn) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-29 09:16:56 +00:00
|
|
|
return nodeSuspendForDuration(target, duration, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-06 15:42:38 +00:00
|
|
|
static int
|
|
|
|
lxcDomainSetMetadata(virDomainPtr dom,
|
|
|
|
int type,
|
|
|
|
const char *metadata,
|
|
|
|
const char *key,
|
|
|
|
const char *uri,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
virLXCDriverConfigPtr cfg = NULL;
|
|
|
|
virCapsPtr caps = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
cfg = virLXCDriverGetConfig(driver);
|
|
|
|
|
|
|
|
if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
|
2014-07-22 15:41:05 +00:00
|
|
|
driver->xmlopt, cfg->stateDir,
|
|
|
|
cfg->configDir, flags);
|
2013-09-06 15:42:38 +00:00
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-09-06 15:42:38 +00:00
|
|
|
virObjectUnlock(vm);
|
|
|
|
virObjectUnref(caps);
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
lxcDomainGetMetadata(virDomainPtr dom,
|
|
|
|
int type,
|
|
|
|
const char *uri,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virLXCDriverPtr driver = dom->conn->privateData;
|
|
|
|
virCapsPtr caps = NULL;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(caps = virLXCDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);
|
|
|
|
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2013-09-06 15:42:38 +00:00
|
|
|
virObjectUnlock(vm);
|
|
|
|
virObjectUnref(caps);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-14 17:49:02 +00:00
|
|
|
static int
|
|
|
|
lxcDomainGetCPUStats(virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
unsigned int nparams,
|
|
|
|
int start_cpu,
|
|
|
|
unsigned int ncpus,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
virLXCDomainObjPrivatePtr priv;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
|
|
|
if (virDomainGetCPUStatsEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("domain is not running"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cgroup CPUACCT controller is not mounted"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (start_cpu == -1)
|
|
|
|
ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
|
|
|
|
params, nparams);
|
|
|
|
else
|
|
|
|
ret = virCgroupGetPercpuStats(priv->cgroup, params,
|
2014-04-03 15:53:43 +00:00
|
|
|
nparams, start_cpu, ncpus, 0);
|
2014-03-25 06:49:26 +00:00
|
|
|
cleanup:
|
2014-02-14 17:49:02 +00:00
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-10 14:16:44 +00:00
|
|
|
static int
|
|
|
|
lxcNodeGetFreePages(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-18 07:47:07 +00:00
|
|
|
static int
|
|
|
|
lxcNodeAllocPages(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-15 14:02:44 +00:00
|
|
|
static int
|
|
|
|
lxcDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
|
|
|
if (!(vm = lxcDomObjFromDomain(dom)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (vm)
|
|
|
|
virObjectUnlock(vm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
/* Function Tables */
|
2015-01-20 16:16:26 +00:00
|
|
|
static virHypervisorDriver lxcHypervisorDriver = {
|
2012-05-10 16:49:29 +00:00
|
|
|
.name = LXC_DRIVER_NAME,
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectOpen = lxcConnectOpen, /* 0.4.2 */
|
|
|
|
.connectClose = lxcConnectClose, /* 0.4.2 */
|
2013-12-13 03:09:01 +00:00
|
|
|
.connectSupportsFeature = lxcConnectSupportsFeature, /* 1.2.2 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectGetVersion = lxcConnectGetVersion, /* 0.4.6 */
|
2013-04-26 16:39:11 +00:00
|
|
|
.connectGetHostname = lxcConnectGetHostname, /* 0.6.3 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectGetSysinfo = lxcConnectGetSysinfo, /* 1.0.5 */
|
2013-04-26 17:21:58 +00:00
|
|
|
.nodeGetInfo = lxcNodeGetInfo, /* 0.6.5 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectGetCapabilities = lxcConnectGetCapabilities, /* 0.6.5 */
|
|
|
|
.connectListDomains = lxcConnectListDomains, /* 0.4.2 */
|
|
|
|
.connectNumOfDomains = lxcConnectNumOfDomains, /* 0.4.2 */
|
|
|
|
.connectListAllDomains = lxcConnectListAllDomains, /* 0.9.13 */
|
|
|
|
.domainCreateXML = lxcDomainCreateXML, /* 0.4.4 */
|
2013-07-09 17:15:45 +00:00
|
|
|
.domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainLookupByID = lxcDomainLookupByID, /* 0.4.2 */
|
|
|
|
.domainLookupByUUID = lxcDomainLookupByUUID, /* 0.4.2 */
|
|
|
|
.domainLookupByName = lxcDomainLookupByName, /* 0.4.2 */
|
|
|
|
.domainSuspend = lxcDomainSuspend, /* 0.7.2 */
|
|
|
|
.domainResume = lxcDomainResume, /* 0.7.2 */
|
|
|
|
.domainDestroy = lxcDomainDestroy, /* 0.4.4 */
|
2011-07-20 16:51:26 +00:00
|
|
|
.domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.domainGetOSType = lxcDomainGetOSType, /* 0.4.2 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
|
|
|
|
.domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
|
|
|
|
.domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
|
2014-07-11 09:26:14 +00:00
|
|
|
.domainSetMemoryFlags = lxcDomainSetMemoryFlags, /* 1.2.7 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
|
|
|
|
.domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
|
2011-11-10 12:35:38 +00:00
|
|
|
.domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
|
|
|
|
.domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
|
|
|
|
.domainGetState = lxcDomainGetState, /* 0.9.2 */
|
2012-01-25 14:12:53 +00:00
|
|
|
.domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
|
|
|
|
.nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
|
2014-02-05 14:10:00 +00:00
|
|
|
.connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */
|
|
|
|
.connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
|
|
|
|
.domainCreate = lxcDomainCreate, /* 0.4.4 */
|
|
|
|
.domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
|
2013-07-09 17:15:45 +00:00
|
|
|
.domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
|
2014-11-18 14:19:38 +00:00
|
|
|
.domainDefineXMLFlags = lxcDomainDefineXMLFlags, /* 1.2.12 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainUndefine = lxcDomainUndefine, /* 0.4.2 */
|
2011-07-20 03:08:21 +00:00
|
|
|
.domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
|
2012-08-14 15:38:27 +00:00
|
|
|
.domainAttachDevice = lxcDomainAttachDevice, /* 1.0.1 */
|
|
|
|
.domainAttachDeviceFlags = lxcDomainAttachDeviceFlags, /* 1.0.1 */
|
|
|
|
.domainDetachDevice = lxcDomainDetachDevice, /* 1.0.1 */
|
|
|
|
.domainDetachDeviceFlags = lxcDomainDetachDeviceFlags, /* 1.0.1 */
|
|
|
|
.domainUpdateDeviceFlags = lxcDomainUpdateDeviceFlags, /* 1.0.1 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
|
|
|
|
.domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.domainGetSchedulerType = lxcDomainGetSchedulerType, /* 0.5.0 */
|
|
|
|
.domainGetSchedulerParameters = lxcDomainGetSchedulerParameters, /* 0.5.0 */
|
|
|
|
.domainGetSchedulerParametersFlags = lxcDomainGetSchedulerParametersFlags, /* 0.9.2 */
|
|
|
|
.domainSetSchedulerParameters = lxcDomainSetSchedulerParameters, /* 0.5.0 */
|
|
|
|
.domainSetSchedulerParametersFlags = lxcDomainSetSchedulerParametersFlags, /* 0.9.2 */
|
2014-02-14 17:49:03 +00:00
|
|
|
.domainBlockStats = lxcDomainBlockStats, /* 1.2.2 */
|
|
|
|
.domainBlockStatsFlags = lxcDomainBlockStatsFlags, /* 1.2.2 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
|
2014-02-14 17:49:00 +00:00
|
|
|
.domainMemoryStats = lxcDomainMemoryStats, /* 1.2.2 */
|
2013-04-26 17:21:58 +00:00
|
|
|
.nodeGetCPUStats = lxcNodeGetCPUStats, /* 0.9.3 */
|
|
|
|
.nodeGetMemoryStats = lxcNodeGetMemoryStats, /* 0.9.3 */
|
|
|
|
.nodeGetCellsFreeMemory = lxcNodeGetCellsFreeMemory, /* 0.6.5 */
|
|
|
|
.nodeGetFreeMemory = lxcNodeGetFreeMemory, /* 0.6.5 */
|
|
|
|
.nodeGetCPUMap = lxcNodeGetCPUMap, /* 1.0.0 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectDomainEventRegister = lxcConnectDomainEventRegister, /* 0.7.0 */
|
|
|
|
.connectDomainEventDeregister = lxcConnectDomainEventDeregister, /* 0.7.0 */
|
|
|
|
.connectIsEncrypted = lxcConnectIsEncrypted, /* 0.7.3 */
|
|
|
|
.connectIsSecure = lxcConnectIsSecure, /* 0.7.3 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainIsActive = lxcDomainIsActive, /* 0.7.3 */
|
|
|
|
.domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
|
|
|
|
.domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectDomainEventRegisterAny = lxcConnectDomainEventRegisterAny, /* 0.8.0 */
|
|
|
|
.connectDomainEventDeregisterAny = lxcConnectDomainEventDeregisterAny, /* 0.8.0 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
|
2013-04-29 09:16:56 +00:00
|
|
|
.nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
|
2013-09-06 15:42:38 +00:00
|
|
|
.domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
|
|
|
|
.domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
|
2014-02-14 17:49:02 +00:00
|
|
|
.domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */
|
2013-04-26 17:21:58 +00:00
|
|
|
.nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
|
|
|
|
.nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
|
2011-11-15 15:26:32 +00:00
|
|
|
.domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
|
2012-11-28 13:26:52 +00:00
|
|
|
.domainShutdown = lxcDomainShutdown, /* 1.0.1 */
|
|
|
|
.domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
|
|
|
|
.domainReboot = lxcDomainReboot, /* 1.0.1 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.domainLxcOpenNamespace = lxcDomainLxcOpenNamespace, /* 1.0.2 */
|
2014-06-10 14:16:44 +00:00
|
|
|
.nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
|
2014-09-25 20:02:21 +00:00
|
|
|
.nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
|
2015-01-15 14:02:44 +00:00
|
|
|
.domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
|
2008-03-21 15:03:37 +00:00
|
|
|
};
|
|
|
|
|
2015-01-20 16:16:26 +00:00
|
|
|
static virConnectDriver lxcConnectDriver = {
|
|
|
|
.hypervisorDriver = &lxcHypervisorDriver,
|
|
|
|
};
|
|
|
|
|
2008-03-27 09:34:06 +00:00
|
|
|
static virStateDriver lxcStateDriver = {
|
2012-05-10 16:49:29 +00:00
|
|
|
.name = LXC_DRIVER_NAME,
|
2013-04-23 12:50:18 +00:00
|
|
|
.stateInitialize = lxcStateInitialize,
|
2013-07-25 12:03:38 +00:00
|
|
|
.stateAutoStart = lxcStateAutoStart,
|
2013-04-23 12:50:18 +00:00
|
|
|
.stateCleanup = lxcStateCleanup,
|
|
|
|
.stateReload = lxcStateReload,
|
2008-03-27 09:34:06 +00:00
|
|
|
};
|
|
|
|
|
2008-03-21 15:03:37 +00:00
|
|
|
int lxcRegister(void)
|
|
|
|
{
|
2015-01-20 16:16:26 +00:00
|
|
|
if (virRegisterConnectDriver(&lxcConnectDriver,
|
|
|
|
true) < 0)
|
2014-03-17 13:35:42 +00:00
|
|
|
return -1;
|
|
|
|
if (virRegisterStateDriver(&lxcStateDriver) < 0)
|
|
|
|
return -1;
|
2008-03-21 15:03:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|