2010-12-16 16:10:54 +00:00
|
|
|
/*
|
|
|
|
* qemu_hotplug.h: QEMU device hotplug management
|
|
|
|
*
|
2012-02-27 11:53:19 +00:00
|
|
|
* Copyright (C) 2006-2012 Red Hat, Inc.
|
2010-12-16 16:10:54 +00:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_hotplug.h"
|
|
|
|
#include "qemu_capabilities.h"
|
|
|
|
#include "qemu_domain.h"
|
|
|
|
#include "qemu_command.h"
|
|
|
|
#include "qemu_bridge_filter.h"
|
|
|
|
#include "qemu_hostdev.h"
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
#include "domain_audit.h"
|
2010-12-16 16:10:54 +00:00
|
|
|
#include "domain_nwfilter.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "virterror_internal.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "pci.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2010-12-16 16:10:54 +00:00
|
|
|
#include "qemu_cgroup.h"
|
2010-10-26 14:04:46 +00:00
|
|
|
#include "locking/domain_lock.h"
|
2011-07-04 06:27:12 +00:00
|
|
|
#include "network/bridge_driver.h"
|
2012-03-28 19:11:09 +00:00
|
|
|
#include "virnetdev.h"
|
|
|
|
#include "virnetdevbridge.h"
|
2012-02-10 21:09:00 +00:00
|
|
|
#include "virnetdevtap.h"
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
int qemuDomainChangeEjectableMedia(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
bool force)
|
|
|
|
{
|
|
|
|
virDomainDiskDefPtr origdisk = NULL;
|
|
|
|
int i;
|
|
|
|
int ret;
|
|
|
|
char *driveAlias = NULL;
|
2011-05-04 12:09:09 +00:00
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (vm->def->disks[i]->bus == disk->bus &&
|
|
|
|
STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
origdisk = vm->def->disks[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!origdisk) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("No device with bus '%s' and target '%s'"),
|
|
|
|
virDomainDiskBusTypeToString(disk->bus),
|
|
|
|
disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!origdisk->info.alias) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing disk device alias name for %s"), origdisk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
|
|
|
|
origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Removable media not supported for %s device"),
|
|
|
|
virDomainDiskDeviceTypeToString(disk->device));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
|
|
|
|
return -1;
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0) {
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
2010-10-26 14:04:46 +00:00
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (!(driveAlias = qemuDeviceDriveHostAlias(origdisk, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (disk->src) {
|
|
|
|
const char *format = NULL;
|
|
|
|
if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
|
|
|
|
if (disk->driverType)
|
|
|
|
format = disk->driverType;
|
|
|
|
else if (origdisk->driverType)
|
|
|
|
format = origdisk->driverType;
|
|
|
|
}
|
|
|
|
ret = qemuMonitorChangeMedia(priv->mon,
|
|
|
|
driveAlias,
|
|
|
|
disk->src, format);
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, origdisk->src, disk->src, "update", ret >= 0);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, origdisk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src);
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, origdisk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on disk %s", origdisk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_FREE(origdisk->src);
|
|
|
|
origdisk->src = disk->src;
|
|
|
|
disk->src = NULL;
|
|
|
|
origdisk->type = disk->type;
|
|
|
|
|
|
|
|
VIR_FREE(driveAlias);
|
|
|
|
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(driveAlias);
|
2010-10-26 14:04:46 +00:00
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on new media %s", disk->src);
|
2010-10-26 14:04:46 +00:00
|
|
|
|
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-13 13:49:50 +00:00
|
|
|
int
|
|
|
|
qemuDomainCheckEjectableMedia(struct qemud_driver *driver,
|
2012-04-02 13:55:08 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
enum qemuDomainAsyncJob asyncJob)
|
2011-09-13 13:49:50 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2012-04-02 13:55:08 +00:00
|
|
|
virHashTablePtr table = NULL;
|
2011-09-13 13:49:50 +00:00
|
|
|
int ret = -1;
|
|
|
|
int i;
|
|
|
|
|
2012-04-02 13:55:08 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
|
|
|
|
table = qemuMonitorGetBlockInfo(priv->mon);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
}
|
2012-01-18 21:01:30 +00:00
|
|
|
|
|
|
|
if (!table)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-09-13 13:49:50 +00:00
|
|
|
for (i = 0; i < vm->def->ndisks; i++) {
|
|
|
|
virDomainDiskDefPtr disk = vm->def->disks[i];
|
2012-01-18 21:01:30 +00:00
|
|
|
struct qemuDomainDiskInfo *info;
|
2011-09-13 13:49:50 +00:00
|
|
|
|
qemu: add new disk device='lun' for bus='virtio' & type='block'
In the past, generic SCSI commands issued from a guest to a virtio
disk were always passed through to the underlying disk by qemu, and
the kernel would also pass them on.
As a result of CVE-2011-4127 (see:
http://seclists.org/oss-sec/2011/q4/536), qemu now honors its
scsi=on|off device option for virtio-blk-pci (which enables/disables
passthrough of generic SCSI commands), and the kernel will only allow
the commands for physical devices (not for partitions or logical
volumes). The default behavior of qemu is still to allow sending
generic SCSI commands to physical disks that are presented to a guest
as virtio-blk-pci devices, but libvirt prefers to disable those
commands in the standard virtio block devices, enabling it only when
specifically requested (hopefully indicating that the requester
understands what they're asking for). For this purpose, a new libvirt
disk device type (device='lun') has been created.
device='lun' is identical to the default device='disk', except that:
1) It is only allowed if bus='virtio', type='block', and the qemu
version is "new enough" to support it ("new enough" == qemu 0.11 or
better), otherwise the domain will fail to start and a
CONFIG_UNSUPPORTED error will be logged).
2) The option "scsi=on" will be added to the -device arg to allow
SG_IO commands (if device !='lun', "scsi=off" will be added to the
-device arg so that SG_IO commands are specifically forbidden).
Guests which continue to use disk device='disk' (the default) will no
longer be able to use SG_IO commands on the disk; those that have
their disk device changed to device='lun' will still be able to use SG_IO
commands.
*docs/formatdomain.html.in - document the new device attribute value.
*docs/schemas/domaincommon.rng - allow it in the RNG
*tests/* - update the args of several existing tests to add scsi=off, and
add one new test that will test scsi=on.
*src/conf/domain_conf.c - update domain XML parser and formatter
*src/qemu/qemu_(command|driver|hotplug).c - treat
VIR_DOMAIN_DISK_DEVICE_LUN *almost* identically to
VIR_DOMAIN_DISK_DEVICE_DISK, except as indicated above.
Note that no support for this new device value was added to any
hypervisor drivers other than qemu, because it's unclear what it might
mean (if anything) to those drivers.
2012-01-05 03:48:38 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
2011-09-13 13:49:50 +00:00
|
|
|
continue;
|
qemu: add new disk device='lun' for bus='virtio' & type='block'
In the past, generic SCSI commands issued from a guest to a virtio
disk were always passed through to the underlying disk by qemu, and
the kernel would also pass them on.
As a result of CVE-2011-4127 (see:
http://seclists.org/oss-sec/2011/q4/536), qemu now honors its
scsi=on|off device option for virtio-blk-pci (which enables/disables
passthrough of generic SCSI commands), and the kernel will only allow
the commands for physical devices (not for partitions or logical
volumes). The default behavior of qemu is still to allow sending
generic SCSI commands to physical disks that are presented to a guest
as virtio-blk-pci devices, but libvirt prefers to disable those
commands in the standard virtio block devices, enabling it only when
specifically requested (hopefully indicating that the requester
understands what they're asking for). For this purpose, a new libvirt
disk device type (device='lun') has been created.
device='lun' is identical to the default device='disk', except that:
1) It is only allowed if bus='virtio', type='block', and the qemu
version is "new enough" to support it ("new enough" == qemu 0.11 or
better), otherwise the domain will fail to start and a
CONFIG_UNSUPPORTED error will be logged).
2) The option "scsi=on" will be added to the -device arg to allow
SG_IO commands (if device !='lun', "scsi=off" will be added to the
-device arg so that SG_IO commands are specifically forbidden).
Guests which continue to use disk device='disk' (the default) will no
longer be able to use SG_IO commands on the disk; those that have
their disk device changed to device='lun' will still be able to use SG_IO
commands.
*docs/formatdomain.html.in - document the new device attribute value.
*docs/schemas/domaincommon.rng - allow it in the RNG
*tests/* - update the args of several existing tests to add scsi=off, and
add one new test that will test scsi=on.
*src/conf/domain_conf.c - update domain XML parser and formatter
*src/qemu/qemu_(command|driver|hotplug).c - treat
VIR_DOMAIN_DISK_DEVICE_LUN *almost* identically to
VIR_DOMAIN_DISK_DEVICE_DISK, except as indicated above.
Note that no support for this new device value was added to any
hypervisor drivers other than qemu, because it's unclear what it might
mean (if anything) to those drivers.
2012-01-05 03:48:38 +00:00
|
|
|
}
|
2011-09-13 13:49:50 +00:00
|
|
|
|
2012-01-18 21:01:30 +00:00
|
|
|
info = qemuMonitorBlockInfoLookup(table, disk->info.alias);
|
|
|
|
if (!info)
|
2011-09-13 13:49:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-01-18 21:01:30 +00:00
|
|
|
if (info->tray_open && disk->src)
|
2011-09-13 13:49:50 +00:00
|
|
|
VIR_FREE(disk->src);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2012-01-18 21:01:30 +00:00
|
|
|
virHashFree(table);
|
2011-09-13 13:49:50 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2011-10-31 19:06:23 +00:00
|
|
|
int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2010-12-16 16:10:54 +00:00
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainDiskDefPtr disk)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
const char* type = virDomainDiskBusTypeToString(disk->bus);
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *devstr = NULL;
|
|
|
|
char *drivestr = NULL;
|
2011-04-26 03:40:01 +00:00
|
|
|
bool releaseaddr = false;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
|
|
|
|
return -1;
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0) {
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
2010-10-26 14:04:46 +00:00
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
|
|
|
|
goto error;
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr = true;
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
|
2011-10-31 19:06:23 +00:00
|
|
|
if (!(drivestr = qemuBuildDriveStr(conn, disk, false, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (!(devstr = qemuBuildDriveDevStr(NULL, disk, 0, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddDrive(priv->mon, drivestr);
|
|
|
|
if (ret == 0) {
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
if (ret < 0) {
|
|
|
|
VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
|
|
|
|
drivestr, devstr);
|
|
|
|
/* XXX should call 'drive_del' on error but this does not
|
|
|
|
exist yet */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2011-10-26 23:40:12 +00:00
|
|
|
virDomainDevicePCIAddress guestAddr = disk->info.addr.pci;
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddPCIDisk(priv->mon,
|
|
|
|
disk->src,
|
|
|
|
type,
|
|
|
|
&guestAddr);
|
|
|
|
if (ret == 0) {
|
|
|
|
disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
memcpy(&disk->info.addr.pci, &guestAddr, sizeof(guestAddr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, NULL, disk->src, "attach", ret >= 0);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, disk);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2010-12-16 16:10:54 +00:00
|
|
|
(disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr &&
|
2011-05-23 07:43:35 +00:00
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
|
|
|
disk->info.addr.pci.slot) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to release PCI address on %s", disk->src);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachPciControllerDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainControllerDefPtr controller)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int ret = -1;
|
|
|
|
const char* type = virDomainControllerTypeToString(controller->type);
|
|
|
|
char *devstr = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2011-04-26 03:40:01 +00:00
|
|
|
bool releaseaddr = false;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ncontrollers ; i++) {
|
|
|
|
if ((vm->def->controllers[i]->type == controller->type) &&
|
|
|
|
(vm->def->controllers[i]->idx == controller->idx)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s:%d already exists"),
|
|
|
|
type, controller->idx);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
|
|
|
|
goto cleanup;
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr = true;
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuAssignDeviceControllerAlias(controller) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
|
|
|
|
controller->model == -1 &&
|
|
|
|
!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI)) {
|
2012-04-17 04:16:04 +00:00
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2011-09-02 13:21:23 +00:00
|
|
|
_("USB controller hotplug unsupported in this QEMU binary"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-12-08 06:41:24 +00:00
|
|
|
if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL))) {
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorAttachPCIDiskController(priv->mon,
|
|
|
|
type,
|
|
|
|
&controller->info.addr.pci);
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
virDomainControllerInsertPreAlloced(vm->def, controller);
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if ((ret != 0) &&
|
2011-05-04 12:09:09 +00:00
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2010-12-16 16:10:54 +00:00
|
|
|
(controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr &&
|
2011-05-23 07:43:35 +00:00
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
|
|
|
controller->info.addr.pci.slot) < 0)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Unable to release PCI address on controller");
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainControllerDefPtr
|
|
|
|
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
int controller)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
virDomainControllerDefPtr cont;
|
2011-05-04 12:09:09 +00:00
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
for (i = 0 ; i < vm->def->ncontrollers ; i++) {
|
|
|
|
cont = vm->def->controllers[i];
|
|
|
|
|
|
|
|
if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cont->idx == controller)
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No SCSI controller present, for backward compatibility we
|
|
|
|
* now hotplug a controller */
|
|
|
|
if (VIR_ALLOC(cont) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
|
2011-01-31 07:55:40 +00:00
|
|
|
cont->idx = controller;
|
2010-12-16 16:10:54 +00:00
|
|
|
cont->model = -1;
|
|
|
|
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_INFO("No SCSI controller present, hotplugging one");
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuDomainAttachPciControllerDevice(driver,
|
2011-05-04 12:09:09 +00:00
|
|
|
vm, cont) < 0) {
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_FREE(cont);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit"));
|
|
|
|
/* cont doesn't need freeing here, since the reference
|
|
|
|
* now held in def->controllers */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-31 19:06:23 +00:00
|
|
|
int qemuDomainAttachSCSIDisk(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2010-12-16 16:10:54 +00:00
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainDiskDefPtr disk)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainControllerDefPtr cont = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
char *devstr = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
|
|
|
|
return -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0) {
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
2010-10-26 14:04:46 +00:00
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
/* We should have an address already, so make sure */
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected disk address type %s"),
|
|
|
|
virDomainDeviceAddressTypeToString(disk->info.type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-10-31 19:06:23 +00:00
|
|
|
if (!(drivestr = qemuBuildDriveStr(conn, disk, false, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
|
2011-05-04 12:09:09 +00:00
|
|
|
cont = qemuDomainFindOrCreateSCSIDiskController(driver, vm, i);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (!cont)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tell clang that "cont" is non-NULL.
|
|
|
|
This is because disk->info.addr.driver.controller is unsigned,
|
|
|
|
and hence the above loop must iterate at least once. */
|
|
|
|
sa_assert (cont);
|
|
|
|
|
|
|
|
if (cont->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("SCSI controller %d was missing its PCI address"), cont->idx);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddDrive(priv->mon, drivestr);
|
|
|
|
if (ret == 0) {
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
if (ret < 0) {
|
|
|
|
VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
|
|
|
|
drivestr, devstr);
|
|
|
|
/* XXX should call 'drive_del' on error but this does not
|
|
|
|
exist yet */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainDeviceDriveAddress driveAddr;
|
|
|
|
ret = qemuMonitorAttachDrive(priv->mon,
|
|
|
|
drivestr,
|
|
|
|
&cont->info.addr.pci,
|
|
|
|
&driveAddr);
|
|
|
|
if (ret == 0) {
|
|
|
|
/* XXX we should probably validate that the addr matches
|
|
|
|
* our existing defined addr instead of overwriting */
|
|
|
|
disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
|
2011-10-21 23:09:17 +00:00
|
|
|
disk->info.addr.drive.bus = driveAddr.bus;
|
|
|
|
disk->info.addr.drive.unit = driveAddr.unit;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, NULL, disk->src, "attach", ret >= 0);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, disk);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-31 19:06:23 +00:00
|
|
|
int qemuDomainAttachUsbMassstorageDevice(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2010-12-16 16:10:54 +00:00
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainDiskDefPtr disk)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int i, ret;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
|
|
|
|
return -1;
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0) {
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
2010-10-26 14:04:46 +00:00
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
/* XXX not correct once we allow attaching a USB CDROM */
|
2010-12-16 16:10:54 +00:00
|
|
|
if (!disk->src) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("disk source path is missing"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
2011-10-31 19:06:23 +00:00
|
|
|
if (!(drivestr = qemuBuildDriveStr(conn, disk, false, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (!(devstr = qemuBuildDriveDevStr(NULL, disk, 0, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddDrive(priv->mon, drivestr);
|
|
|
|
if (ret == 0) {
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
if (ret < 0) {
|
|
|
|
VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
|
|
|
|
drivestr, devstr);
|
|
|
|
/* XXX should call 'drive_del' on error but this does not
|
|
|
|
exist yet */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorAddUSBDisk(priv->mon, disk->src);
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, NULL, disk->src, "attach", ret >= 0);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, disk);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* XXX conn required for network -> bridge resolution */
|
|
|
|
int qemuDomainAttachNetDevice(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainNetDefPtr net)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *tapfd_name = NULL;
|
|
|
|
int tapfd = -1;
|
2011-03-09 04:43:33 +00:00
|
|
|
char *vhostfd_name = NULL;
|
|
|
|
int vhostfd = -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
char *nicstr = NULL;
|
|
|
|
char *netstr = NULL;
|
2012-02-10 21:09:00 +00:00
|
|
|
virNetDevVPortProfilePtr vport = NULL;
|
2010-12-16 16:10:54 +00:00
|
|
|
int ret = -1;
|
|
|
|
virDomainDevicePCIAddress guestAddr;
|
|
|
|
int vlan;
|
2011-04-26 03:40:01 +00:00
|
|
|
bool releaseaddr = false;
|
2011-07-04 06:27:12 +00:00
|
|
|
bool iface_connected = false;
|
|
|
|
int actualType;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
qemu: support type=hostdev network device live hotplug attach/detach
qemuDomainAttachNetDevice
- re-ordered some things at start of function because
networkAllocateActualDevice should always be run and a slot
in def->nets always allocated, but host_net_add isn't needed
if the actual type is hostdev.
- if actual type is hostdev, defer to
qemuDomainAttachHostDevice (which will reach up to the NetDef
for things like MAC address when necessary). After return
from qemuDomainAttachHostDevice, slip directly to cleanup,
since the rest of the function is specific to emulated net
devices.
- put assignment of new NetDef into expanded def->nets down
below cleanup: (but only on success) since it is also needed
for emulated and hostdev net devices.
qemuDomainDetachHostDevice
- after locating the exact device to detach, check if it's a
network device and, if so, use toplevel
qemuDomainDetachNetDevice instead so that the def->nets list
is properly updated, and 'actual device' properly returned to
network pool if appropriate. Otherwise, for normal hostdevs,
call the lower level qemuDomainDetachThisDevice.
qemuDomainDetachNetDevice
- This is where it gets a bit tricky. After locating the device
on the def->nets list, if the network device type == hostdev,
call the *lower level* qemuDomainDetachThisDevice (which will
reach back up to the parent net device for MAC address /
virtualport when appropriate, then clear the device out of
def->hostdevs) before skipping past all the emulated
net-device-specific code to cleanup:, where the network
device is removed from def->nets, and the network device
object is freed.
In short, any time a hostdev-type network device is detached, we must
go through the toplevel virDomaineDetachNetDevice function first and
last, to make sure 1) the def->nnets list is properly managed, and 2)
any device allocated with networkAllocateActualDevice is properly
freed. At the same time, in the middle we need to go through the
lower-level vidDomainDetach*This*HostDevice to be sure that 1) the
def->hostdevs list is properly managed, 2) the PCI device is properly
detached from the guest and reattached to the host (if appropriate),
and 3) any higher level teardown is called at the appropriate time, by
reaching back up to the NetDef config (part (3) will be covered in a
separate patch).
2012-02-27 19:20:17 +00:00
|
|
|
/* preallocate new slot for device */
|
|
|
|
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) {
|
|
|
|
virReportOOMError();
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
if (networkAllocateActualDevice(net) < 0)
|
qemu: support type=hostdev network device live hotplug attach/detach
qemuDomainAttachNetDevice
- re-ordered some things at start of function because
networkAllocateActualDevice should always be run and a slot
in def->nets always allocated, but host_net_add isn't needed
if the actual type is hostdev.
- if actual type is hostdev, defer to
qemuDomainAttachHostDevice (which will reach up to the NetDef
for things like MAC address when necessary). After return
from qemuDomainAttachHostDevice, slip directly to cleanup,
since the rest of the function is specific to emulated net
devices.
- put assignment of new NetDef into expanded def->nets down
below cleanup: (but only on success) since it is also needed
for emulated and hostdev net devices.
qemuDomainDetachHostDevice
- after locating the exact device to detach, check if it's a
network device and, if so, use toplevel
qemuDomainDetachNetDevice instead so that the def->nets list
is properly updated, and 'actual device' properly returned to
network pool if appropriate. Otherwise, for normal hostdevs,
call the lower level qemuDomainDetachThisDevice.
qemuDomainDetachNetDevice
- This is where it gets a bit tricky. After locating the device
on the def->nets list, if the network device type == hostdev,
call the *lower level* qemuDomainDetachThisDevice (which will
reach back up to the parent net device for MAC address /
virtualport when appropriate, then clear the device out of
def->hostdevs) before skipping past all the emulated
net-device-specific code to cleanup:, where the network
device is removed from def->nets, and the network device
object is freed.
In short, any time a hostdev-type network device is detached, we must
go through the toplevel virDomaineDetachNetDevice function first and
last, to make sure 1) the def->nnets list is properly managed, and 2)
any device allocated with networkAllocateActualDevice is properly
freed. At the same time, in the middle we need to go through the
lower-level vidDomainDetach*This*HostDevice to be sure that 1) the
def->hostdevs list is properly managed, 2) the PCI device is properly
detached from the guest and reattached to the host (if appropriate),
and 3) any higher level teardown is called at the appropriate time, by
reaching back up to the NetDef config (part (3) will be covered in a
separate patch).
2012-02-27 19:20:17 +00:00
|
|
|
return -1;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
actualType = virDomainNetGetActualType(net);
|
qemu: support type=hostdev network device live hotplug attach/detach
qemuDomainAttachNetDevice
- re-ordered some things at start of function because
networkAllocateActualDevice should always be run and a slot
in def->nets always allocated, but host_net_add isn't needed
if the actual type is hostdev.
- if actual type is hostdev, defer to
qemuDomainAttachHostDevice (which will reach up to the NetDef
for things like MAC address when necessary). After return
from qemuDomainAttachHostDevice, slip directly to cleanup,
since the rest of the function is specific to emulated net
devices.
- put assignment of new NetDef into expanded def->nets down
below cleanup: (but only on success) since it is also needed
for emulated and hostdev net devices.
qemuDomainDetachHostDevice
- after locating the exact device to detach, check if it's a
network device and, if so, use toplevel
qemuDomainDetachNetDevice instead so that the def->nets list
is properly updated, and 'actual device' properly returned to
network pool if appropriate. Otherwise, for normal hostdevs,
call the lower level qemuDomainDetachThisDevice.
qemuDomainDetachNetDevice
- This is where it gets a bit tricky. After locating the device
on the def->nets list, if the network device type == hostdev,
call the *lower level* qemuDomainDetachThisDevice (which will
reach back up to the parent net device for MAC address /
virtualport when appropriate, then clear the device out of
def->hostdevs) before skipping past all the emulated
net-device-specific code to cleanup:, where the network
device is removed from def->nets, and the network device
object is freed.
In short, any time a hostdev-type network device is detached, we must
go through the toplevel virDomaineDetachNetDevice function first and
last, to make sure 1) the def->nnets list is properly managed, and 2)
any device allocated with networkAllocateActualDevice is properly
freed. At the same time, in the middle we need to go through the
lower-level vidDomainDetach*This*HostDevice to be sure that 1) the
def->hostdevs list is properly managed, 2) the PCI device is properly
detached from the guest and reattached to the host (if appropriate),
and 3) any higher level teardown is called at the appropriate time, by
reaching back up to the NetDef config (part (3) will be covered in a
separate patch).
2012-02-27 19:20:17 +00:00
|
|
|
|
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
|
/* This is really a "smart hostdev", so it should be attached
|
|
|
|
* as a hostdev (the hostdev code will reach over into the
|
|
|
|
* netdev-specific code as appropriate), then also added to
|
|
|
|
* the nets list (see cleanup:) if successful.
|
|
|
|
*/
|
|
|
|
ret = qemuDomainAttachHostDevice(driver, vm,
|
|
|
|
virDomainNetGetActualHostdev(net));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_HOST_NET_ADD)) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("installed qemu version does not support host_net_add"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-07-04 01:57:45 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
audit: audit use of /dev/net/tun, /dev/tapN, /dev/vhost-net
Opening raw network devices with the intent of passing those fds to
qemu is worth an audit point. This makes a multi-part audit: first,
we audit the device(s) that libvirt opens on behalf of the MAC address
of a to-be-created interface (which can independently succeed or
fail), then we audit whether qemu actually started the network device
with the same MAC (so searching backwards for successful audits with
the same MAC will show which fd(s) qemu is actually using). Note that
it is possible for the fd to be successfully opened but no attempt
made to pass the fd to qemu (for example, because intermediate
nwfilter operations failed) - no interface start audit will occur in
that case; so the audit for a successful opened fd does not imply
rights given to qemu unless there is a followup audit about the
attempt to start a new interface.
Likewise, when a network device is hot-unplugged, there is only one
audit message about the MAC being discontinued; again, searching back
to the earlier device open audits will show which fds that qemu quits
using (and yes, I checked via /proc/<qemu-pid>/fd that qemu _does_
close out the fds associated with an interface on hot-unplug). The
code would require much more refactoring to be able to definitively
state which device(s) were discontinued at that point, since we
currently don't record anywhere in the XML whether /dev/vhost-net was
opened for a given interface.
* src/qemu/qemu_audit.h (qemuAuditNetDevice): New prototype.
* src/qemu/qemu_audit.c (qemuAuditNetDevice): New function.
* src/qemu/qemu_command.h (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Adjust prototype.
* src/qemu/qemu_command.c (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Add audit points and
adjust parameters.
(qemuBuildCommandLine): Adjust caller.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
2011-03-08 18:00:59 +00:00
|
|
|
if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net,
|
2011-05-04 12:09:09 +00:00
|
|
|
priv->qemuCaps)) < 0)
|
2011-07-04 06:27:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
iface_connected = true;
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
|
2011-03-09 04:43:33 +00:00
|
|
|
goto cleanup;
|
2011-07-04 01:57:45 +00:00
|
|
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
2011-11-10 16:16:22 +00:00
|
|
|
if ((tapfd = qemuPhysIfaceConnect(vm->def, driver, net,
|
2011-05-04 12:09:09 +00:00
|
|
|
priv->qemuCaps,
|
Rename Macvtap management APIs
In preparation for code re-organization, rename the Macvtap
management APIs to have the following patterns
virNetDevMacVLanXXXXX - macvlan/macvtap interface management
virNetDevVPortProfileXXXX - virtual port profile management
* src/util/macvtap.c, src/util/macvtap.h: Rename APIs
* src/conf/domain_conf.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_command.h,
src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/qemu/qemu_process.h: Update for renamed APIs
2011-11-02 16:51:01 +00:00
|
|
|
VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0)
|
2011-07-04 06:27:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
iface_connected = true;
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
|
2011-03-09 04:43:33 +00:00
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NET_NAME) ||
|
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr = true;
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
vlan = -1;
|
|
|
|
} else {
|
|
|
|
vlan = qemuDomainNetVLAN(net);
|
|
|
|
|
|
|
|
if (vlan < 0) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Unable to attach network devices without vlan"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tapfd != -1) {
|
|
|
|
if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2011-03-09 04:43:33 +00:00
|
|
|
if (vhostfd != -1) {
|
|
|
|
if (virAsprintf(&vhostfd_name, "vhostfd-%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (!(netstr = qemuBuildHostNetStr(net, ',',
|
2011-03-09 04:43:33 +00:00
|
|
|
-1, tapfd_name, vhostfd_name)))
|
2011-03-16 02:21:45 +00:00
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
} else {
|
|
|
|
if (!(netstr = qemuBuildHostNetStr(net, ' ',
|
2011-03-09 04:43:33 +00:00
|
|
|
vlan, tapfd_name, vhostfd_name)))
|
2011-03-16 02:21:45 +00:00
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2011-03-16 02:21:45 +00:00
|
|
|
if (qemuMonitorAddNetdev(priv->mon, netstr, tapfd, tapfd_name,
|
|
|
|
vhostfd, vhostfd_name) < 0) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", false);
|
2011-03-16 02:21:45 +00:00
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
} else {
|
2011-03-16 02:21:45 +00:00
|
|
|
if (qemuMonitorAddHostNetwork(priv->mon, netstr, tapfd, tapfd_name,
|
|
|
|
vhostfd, vhostfd_name) < 0) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", false);
|
2011-03-16 02:21:45 +00:00
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
2011-03-09 04:43:33 +00:00
|
|
|
VIR_FORCE_CLOSE(vhostfd);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2011-05-26 14:15:01 +00:00
|
|
|
if (!(nicstr = qemuBuildNicDevStr(net, vlan, 0, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto try_remove;
|
|
|
|
} else {
|
|
|
|
if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
|
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", false);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
} else {
|
2011-10-26 23:40:12 +00:00
|
|
|
guestAddr = net->info.addr.pci;
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
|
|
|
|
&guestAddr) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", false);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
memcpy(&net->info.addr.pci, &guestAddr, sizeof(guestAddr));
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-09-06 08:23:47 +00:00
|
|
|
/* set link state */
|
|
|
|
if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
|
|
|
|
if (!net->info.alias) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("device alias not found: cannot set link state to down"));
|
|
|
|
} else {
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
|
|
|
|
if (qemuMonitorSetLink(priv->mon, net->info.alias, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", false);
|
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("setting of link state not supported: Link is up"));
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
}
|
|
|
|
/* link set to down */
|
|
|
|
}
|
|
|
|
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditNet(vm, NULL, net, "attach", true);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
qemu: support type=hostdev network device live hotplug attach/detach
qemuDomainAttachNetDevice
- re-ordered some things at start of function because
networkAllocateActualDevice should always be run and a slot
in def->nets always allocated, but host_net_add isn't needed
if the actual type is hostdev.
- if actual type is hostdev, defer to
qemuDomainAttachHostDevice (which will reach up to the NetDef
for things like MAC address when necessary). After return
from qemuDomainAttachHostDevice, slip directly to cleanup,
since the rest of the function is specific to emulated net
devices.
- put assignment of new NetDef into expanded def->nets down
below cleanup: (but only on success) since it is also needed
for emulated and hostdev net devices.
qemuDomainDetachHostDevice
- after locating the exact device to detach, check if it's a
network device and, if so, use toplevel
qemuDomainDetachNetDevice instead so that the def->nets list
is properly updated, and 'actual device' properly returned to
network pool if appropriate. Otherwise, for normal hostdevs,
call the lower level qemuDomainDetachThisDevice.
qemuDomainDetachNetDevice
- This is where it gets a bit tricky. After locating the device
on the def->nets list, if the network device type == hostdev,
call the *lower level* qemuDomainDetachThisDevice (which will
reach back up to the parent net device for MAC address /
virtualport when appropriate, then clear the device out of
def->hostdevs) before skipping past all the emulated
net-device-specific code to cleanup:, where the network
device is removed from def->nets, and the network device
object is freed.
In short, any time a hostdev-type network device is detached, we must
go through the toplevel virDomaineDetachNetDevice function first and
last, to make sure 1) the def->nnets list is properly managed, and 2)
any device allocated with networkAllocateActualDevice is properly
freed. At the same time, in the middle we need to go through the
lower-level vidDomainDetach*This*HostDevice to be sure that 1) the
def->hostdevs list is properly managed, 2) the PCI device is properly
detached from the guest and reattached to the host (if appropriate),
and 3) any higher level teardown is called at the appropriate time, by
reaching back up to the NetDef config (part (3) will be covered in a
separate patch).
2012-02-27 19:20:17 +00:00
|
|
|
if (!ret) {
|
|
|
|
vm->def->nets[vm->def->nnets++] = net;
|
|
|
|
} else {
|
2011-07-04 06:27:12 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
|
|
|
(net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
|
|
|
releaseaddr &&
|
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
|
|
|
net->info.addr.pci.slot) < 0)
|
|
|
|
VIR_WARN("Unable to release PCI address on NIC");
|
|
|
|
|
2012-02-28 03:43:23 +00:00
|
|
|
if (iface_connected) {
|
2011-07-04 06:27:12 +00:00
|
|
|
virDomainConfNWFilterTeardown(net);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-02-28 03:43:23 +00:00
|
|
|
vport = virDomainNetGetActualVirtPortProfile(net);
|
|
|
|
if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
|
|
|
|
ignore_value(virNetDevOpenvswitchRemovePort(
|
|
|
|
virDomainNetGetActualBridgeName(net), net->ifname));
|
|
|
|
}
|
2012-02-10 21:09:00 +00:00
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
networkReleaseActualDevice(net);
|
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
VIR_FREE(nicstr);
|
|
|
|
VIR_FREE(netstr);
|
|
|
|
VIR_FREE(tapfd_name);
|
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
2011-03-09 04:43:33 +00:00
|
|
|
VIR_FREE(vhostfd_name);
|
|
|
|
VIR_FORCE_CLOSE(vhostfd);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
try_remove:
|
|
|
|
if (!virDomainObjIsActive(vm))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (vlan < 0) {
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
char *netdev_name;
|
|
|
|
if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
|
|
|
|
VIR_WARN("Failed to remove network backend for netdev %s",
|
|
|
|
netdev_name);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
VIR_FREE(netdev_name);
|
|
|
|
} else {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Unable to remove network backend");
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
char *hostnet_name;
|
|
|
|
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
|
|
|
|
VIR_WARN("Failed to remove network backend for vlan %d, net %s",
|
|
|
|
vlan, hostnet_name);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
VIR_FREE(hostnet_name);
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachHostPciDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainHostdevDefPtr hostdev)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int ret;
|
|
|
|
char *devstr = NULL;
|
|
|
|
int configfd = -1;
|
|
|
|
char *configfd_name = NULL;
|
2011-04-26 03:40:01 +00:00
|
|
|
bool releaseaddr = false;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-06 01:12:44 +00:00
|
|
|
if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
|
|
|
|
&hostdev, 1) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
|
|
|
|
goto error;
|
2012-01-31 09:16:54 +00:00
|
|
|
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr = true;
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_PCI_CONFIGFD)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
configfd = qemuOpenPCIConfig(hostdev);
|
|
|
|
if (configfd >= 0) {
|
|
|
|
if (virAsprintf(&configfd_name, "fd-%s",
|
2012-01-31 09:16:54 +00:00
|
|
|
hostdev->info->alias) < 0) {
|
2010-12-16 16:10:54 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit during hotplug"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-02-01 16:22:01 +00:00
|
|
|
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name,
|
2011-05-04 12:09:09 +00:00
|
|
|
priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-03-15 23:10:16 +00:00
|
|
|
ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr,
|
|
|
|
configfd, configfd_name);
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
} else {
|
2012-01-31 09:16:54 +00:00
|
|
|
virDomainDevicePCIAddress guestAddr = hostdev->info->addr.pci;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddPCIHostDevice(priv->mon,
|
|
|
|
&hostdev->source.subsys.u.pci,
|
|
|
|
&guestAddr);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
memcpy(&hostdev->info->addr.pci, &guestAddr, sizeof(guestAddr));
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(configfd_name);
|
|
|
|
VIR_FORCE_CLOSE(configfd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2012-01-31 09:16:54 +00:00
|
|
|
(hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
2011-04-26 03:40:01 +00:00
|
|
|
releaseaddr &&
|
2011-05-23 07:43:35 +00:00
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
2012-01-31 09:16:54 +00:00
|
|
|
hostdev->info->addr.pci.slot) < 0)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Unable to release PCI address on host device");
|
2010-12-16 16:10:54 +00:00
|
|
|
|
qemu: Do not reattach PCI device used by other domain when shutdown
When failing on starting a domain, it tries to reattach all the PCI
devices defined in the domain conf, regardless of whether the devices
are still used by other domain. This will cause the devices to be deleted
from the list qemu_driver->activePciHostdevs, thus the devices will be
thought as usable even if it's not true. And following commands
nodedev-{reattach,reset} will be successful.
How to reproduce:
1) Define two domains with same PCI device defined in the confs.
2) # virsh start domain1
3) # virsh start domain2
4) # virsh nodedev-reattach $pci_device
You will see the device will be reattached to host successfully.
As pciDeviceReattach just check if the device is still used by
other domain via checking if the device is in list driver->activePciHostdevs,
however, the device is deleted from the list by step 2).
This patch is to prohibit the bug by:
1) Prohibit a domain starting or device attachment right at
preparation period (qemuPrepareHostdevPCIDevices) if the
device is in list driver->activePciHostdevs, which means
it's used by other domain.
2) Introduces a new field for struct _pciDevice, (const char *used_by),
it will be set as the domain name at preparation period,
(qemuPrepareHostdevPCIDevices). Thus we can prohibit deleting
the device from driver->activePciHostdevs if it's still used by
other domain when stopping the domain process.
* src/pci.h (define two internal functions, pciDeviceSetUsedBy and
pciDevceGetUsedBy)
* src/pci.c (new field "const char *used_by" for struct _pciDevice,
implementations for the two new functions)
* src/libvirt_private.syms (Add the two new internal functions)
* src/qemu_hostdev.h (Modify the definition of functions
qemuPrepareHostdevPCIDevices, and qemuDomainReAttachHostdevDevices)
* src/qemu_hostdev.c (Prohibit preparation and don't delete the
device from activePciHostdevs list if it's still used by other domain)
* src/qemu_hotplug.c (Update function usage, as the definitions are
changed)
Signed-off-by: Eric Blake <eblake@redhat.com>
2011-10-13 04:05:04 +00:00
|
|
|
qemuDomainReAttachHostdevDevices(driver, vm->def->name, &hostdev, 1);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(configfd_name);
|
|
|
|
VIR_FORCE_CLOSE(configfd);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-02 15:09:14 +00:00
|
|
|
int qemuDomainAttachRedirdevDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainRedirdevDefPtr redirdev)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
if (qemuAssignDeviceRedirdevAlias(vm->def, redirdev, -1) < 0)
|
|
|
|
goto error;
|
|
|
|
if (!(devstr = qemuBuildRedirdevDevStr(redirdev, priv->qemuCaps)))
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->redirdevs, vm->def->nredirdevs+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE))
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
else
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
vm->def->redirdevs[vm->def->nredirdevs++] = redirdev;
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainHostdevDefPtr hostdev)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
|
|
|
|
goto error;
|
2011-09-02 13:28:27 +00:00
|
|
|
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, priv->qemuCaps)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
usbDevice *usb;
|
2011-03-23 02:02:15 +00:00
|
|
|
qemuCgroupData data;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-01-28 03:39:44 +00:00
|
|
|
_("Unable to find cgroup for %s"),
|
2010-12-16 16:10:54 +00:00
|
|
|
vm->def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
|
|
|
|
hostdev->source.subsys.u.usb.device)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
2011-03-23 02:02:15 +00:00
|
|
|
data.vm = vm;
|
|
|
|
data.cgroup = cgroup;
|
2011-02-16 02:18:40 +00:00
|
|
|
if (usbDeviceFileIterate(usb, qemuSetupHostUsbDeviceCgroup, &data) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE))
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
else
|
|
|
|
ret = qemuMonitorAddUSBDeviceExact(priv->mon,
|
|
|
|
hostdev->source.subsys.u.usb.bus,
|
|
|
|
hostdev->source.subsys.u.usb.device);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainAttachHostDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainHostdevDefPtr hostdev)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
2012-05-06 14:45:05 +00:00
|
|
|
usbDeviceList *list;
|
|
|
|
usbDevice *usb = NULL;
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev mode '%s' not supported"),
|
|
|
|
virDomainHostdevModeTypeToString(hostdev->mode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
if (!(list = usbDeviceListNew()))
|
|
|
|
goto cleanup;
|
2012-05-04 07:49:58 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
|
|
|
unsigned vendor = hostdev->source.subsys.u.usb.vendor;
|
|
|
|
unsigned product = hostdev->source.subsys.u.usb.product;
|
|
|
|
unsigned bus = hostdev->source.subsys.u.usb.bus;
|
|
|
|
unsigned device = hostdev->source.subsys.u.usb.device;
|
2011-12-21 17:58:29 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
if (vendor && bus) {
|
|
|
|
usb = usbFindDevice(vendor, product, bus, device);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
} else if (vendor && !bus) {
|
|
|
|
usbDeviceList *devs = usbFindDeviceByVendor(vendor, product);
|
|
|
|
if (!devs)
|
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
if (usbDeviceListCount(devs) > 1) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("multiple USB devices for %x:%x, "
|
|
|
|
"use <address> to specify one"), vendor, product);
|
|
|
|
usbDeviceListFree(devs);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
usb = usbDeviceListGet(devs, 0);
|
|
|
|
usbDeviceListSteal(devs, usb);
|
|
|
|
usbDeviceListFree(devs);
|
2012-05-04 07:49:58 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
|
|
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
} else if (!vendor && bus) {
|
|
|
|
usb = usbFindDeviceByBus(bus, device);
|
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
if (!usb)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (usbDeviceListAdd(list, usb) < 0) {
|
|
|
|
usbFreeDevice(usb);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-05-17 11:40:52 +00:00
|
|
|
if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0) {
|
|
|
|
usb = NULL;
|
2012-05-06 14:45:05 +00:00
|
|
|
goto cleanup;
|
2012-05-17 11:40:52 +00:00
|
|
|
}
|
2012-05-06 14:45:05 +00:00
|
|
|
|
|
|
|
usbDeviceListSteal(list, usb);
|
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetHostdevLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, hostdev) < 0)
|
2012-05-06 14:45:05 +00:00
|
|
|
goto cleanup;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
switch (hostdev->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
|
|
|
if (qemuDomainAttachHostPciDevice(driver, vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
hostdev) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
|
|
if (qemuDomainAttachHostUsbDevice(driver, vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
hostdev) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev subsys type '%s' not supported"),
|
|
|
|
virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
usbDeviceListFree(list);
|
2010-12-16 16:10:54 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreHostdevLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, hostdev) < 0)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Unable to restore host device labelling on hotplug fail");
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-05-06 14:45:05 +00:00
|
|
|
cleanup:
|
|
|
|
usbDeviceListFree(list);
|
2012-05-11 06:29:15 +00:00
|
|
|
if (usb)
|
|
|
|
usbDeviceListSteal(driver->activeUsbHostdevs, usb);
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-06 08:23:47 +00:00
|
|
|
static virDomainNetDefPtr qemuDomainFindNet(virDomainObjPtr vm,
|
|
|
|
virDomainNetDefPtr dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < vm->def->nnets; i++) {
|
|
|
|
if (memcmp(vm->def->nets[i]->mac, dev->mac, VIR_MAC_BUFLEN) == 0)
|
|
|
|
return vm->def->nets[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-28 19:11:09 +00:00
|
|
|
static
|
|
|
|
int qemuDomainChangeNetBridge(virDomainObjPtr vm,
|
|
|
|
virDomainNetDefPtr olddev,
|
|
|
|
virDomainNetDefPtr newdev)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *oldbridge = olddev->data.bridge.brname;
|
|
|
|
char *newbridge = newdev->data.bridge.brname;
|
|
|
|
|
|
|
|
VIR_DEBUG("Change bridge for interface %s: %s -> %s",
|
|
|
|
olddev->ifname, oldbridge, newbridge);
|
|
|
|
|
|
|
|
if (virNetDevExists(newbridge) != 1) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("bridge %s doesn't exist"), newbridge);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldbridge) {
|
|
|
|
ret = virNetDevBridgeRemovePort(oldbridge, olddev->ifname);
|
|
|
|
virDomainAuditNet(vm, olddev, NULL, "detach", ret == 0);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* move newbridge into olddev now so Audit log is correct */
|
|
|
|
olddev->data.bridge.brname = newbridge;
|
|
|
|
ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
|
|
|
|
virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
/* restore oldbridge to olddev */
|
|
|
|
olddev->data.bridge.brname = oldbridge;
|
|
|
|
ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
|
|
|
|
virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("unable to recover former state by adding port"
|
|
|
|
"to bridge %s"), oldbridge);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* oldbridge no longer needed, and newbridge moved to olddev */
|
|
|
|
VIR_FREE(oldbridge);
|
|
|
|
newdev->data.bridge.brname = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-06 08:23:47 +00:00
|
|
|
int qemuDomainChangeNetLinkState(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainNetDefPtr dev,
|
|
|
|
int linkstate)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
VIR_DEBUG("dev: %s, state: %d", dev->info.alias, linkstate);
|
|
|
|
|
|
|
|
if (!dev->info.alias) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("can't change link state: device alias not found"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
ret = qemuMonitorSetLink(priv->mon, dev->info.alias, linkstate);
|
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* modify the device configuration */
|
|
|
|
dev->linkstate = linkstate;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainChangeNet(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainPtr dom ATTRIBUTE_UNUSED,
|
|
|
|
virDomainNetDefPtr dev)
|
|
|
|
|
|
|
|
{
|
|
|
|
virDomainNetDefPtr olddev = qemuDomainFindNet(vm, dev);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!olddev) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot find existing network device to modify"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (olddev->type != dev->type) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot change network interface type"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (olddev->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.ethernet.dev, dev->data.ethernet.dev) ||
|
config: report error when script given for inappropriate interface type
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633
Although scripts are not used by interfaces of type other than
"ethernet" in qemu, due to the fact that the parser stores the script
name in a union that is only valid when type is ethernet or bridge,
there is no way for anyone except the parser itself to catch the
problem of specifying an interface script for an inappropriate
interface type (by the time the parsed data gets back to the code that
called the parser, all evidence that a script was specified is
forgotten).
Since the parser itself should be agnostic to which type of interface
allows scripts (an example of why: a script specified for an interface
of type bridge is valid for xen domains, but not for qemu domains),
the solution here is to move the script out of the union(s) in the
DomainNetDef, always populate it when specified (regardless of
interface type), and let the driver decide whether or not it is
appropriate.
Currently the qemu, xen, libxml, and uml drivers recognize the script
parameter and do something with it (the uml driver only to report that
it isn't supported). Those drivers have been updated to log a
CONFIG_UNSUPPORTED error when a script is specified for an interface
type that's inappropriate for that particular hypervisor.
(NB: There was earlier discussion of solving this problem by adding a
VALIDATE flag to all libvirt APIs that accept XML, which would cause
the XML to be validated against the RNG files. One statement during
that discussion was that the RNG shouldn't contain hypervisor-specific
things, though, and a proper solution to this problem would require
that (again, because a script for an interface of type "bridge" is
accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
|
|
|
STRNEQ_NULLABLE(olddev->script, dev->script) ||
|
2011-09-06 08:23:47 +00:00
|
|
|
STRNEQ_NULLABLE(olddev->data.ethernet.ipaddr, dev->data.ethernet.ipaddr)) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify ethernet network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.socket.address, dev->data.socket.address) ||
|
|
|
|
olddev->data.socket.port != dev->data.socket.port) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify network socket device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.network.name, dev->data.network.name) ||
|
|
|
|
STRNEQ_NULLABLE(olddev->data.network.portgroup, dev->data.network.portgroup) ||
|
2011-11-02 14:43:16 +00:00
|
|
|
!virNetDevVPortProfileEqual(olddev->data.network.virtPortProfile, dev->data.network.virtPortProfile)) {
|
2011-09-06 08:23:47 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2012-03-28 19:11:09 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
/* allow changing brname, but not portprofile */
|
|
|
|
if (!virNetDevVPortProfileEqual(olddev->data.bridge.virtPortProfile,
|
|
|
|
dev->data.bridge.virtPortProfile)) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify bridge network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-09-06 08:23:47 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.internal.name, dev->data.internal.name)) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify internal network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.direct.linkdev, dev->data.direct.linkdev) ||
|
|
|
|
olddev->data.direct.mode != dev->data.direct.mode ||
|
2011-11-02 14:43:16 +00:00
|
|
|
!virNetDevVPortProfileEqual(olddev->data.direct.virtPortProfile, dev->data.direct.virtPortProfile)) {
|
2011-09-06 08:23:47 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify direct network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to change config on '%s' network type"),
|
|
|
|
virDomainNetTypeToString(dev->type));
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* all other unmodifiable parameters */
|
|
|
|
if (STRNEQ_NULLABLE(olddev->model, dev->model) ||
|
|
|
|
STRNEQ_NULLABLE(olddev->filter, dev->filter)) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if device name has been set, if no, retain the autogenerated one */
|
|
|
|
if (dev->ifname &&
|
|
|
|
STRNEQ_NULLABLE(olddev->ifname, dev->ifname)) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("cannot modify network device configuration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-28 19:11:09 +00:00
|
|
|
if (olddev->type == VIR_DOMAIN_NET_TYPE_BRIDGE
|
|
|
|
&& STRNEQ_NULLABLE(olddev->data.bridge.brname,
|
|
|
|
dev->data.bridge.brname)) {
|
|
|
|
if ((ret = qemuDomainChangeNetBridge(vm, olddev, dev)) < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-09-06 08:23:47 +00:00
|
|
|
if (olddev->linkstate != dev->linkstate) {
|
|
|
|
if ((ret = qemuDomainChangeNetLinkState(driver, vm, olddev, dev->linkstate)) < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
static virDomainGraphicsDefPtr qemuDomainFindGraphics(virDomainObjPtr vm,
|
|
|
|
virDomainGraphicsDefPtr dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ngraphics ; i++) {
|
|
|
|
if (vm->def->graphics[i]->type == dev->type)
|
|
|
|
return vm->def->graphics[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuDomainChangeGraphics(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainGraphicsDefPtr dev)
|
|
|
|
{
|
|
|
|
virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
|
conf: add <listen> subelement to domain <graphics> element
Once it's plugged in, the <listen> element will be an optional
replacement for the "listen" attribute that graphics elements already
have. If the <listen> element is type='address', it will have an
attribute called 'address' which will contain an IP address or dns
name that the guest's display server should listen on. If, however,
type='network', the <listen> element should have an attribute called
'network' that will be set to the name of a network configuration to
get the IP address from.
* docs/schemas/domain.rng: updated to allow the <listen> element
* docs/formatdomain.html.in: document the <listen> element and its
attributes.
* src/conf/domain_conf.[hc]:
1) The domain parser, formatter, and data structure are modified to
support 0 or more <listen> subelements to each <graphics>
element. The old style "legacy" listen attribute is also still
accepted, and will be stored internally just as if it were a
separate <listen> element. On output (i.e. format), the address
attribute of the first <listen> element of type 'address' will be
duplicated in the legacy "listen" attribute of the <graphic>
element.
2) The "listenAddr" attribute has been removed from the unions in
virDomainGRaphicsDef for graphics types vnc, rdp, and spice.
This attribute is now in the <listen> subelement (aka
virDomainGraphicsListenDef)
3) Helper functions were written to provide simple access
(both Get and Set) to the listen elements and their attributes.
* src/libvirt_private.syms: export the listen helper functions
* src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c,
src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c
Modify all these files to use the listen helper functions rather
than directly referencing the (now missing) listenAddr
attribute. There can be multiple <listen> elements to a single
<graphics>, but the drivers all currently only support one, so all
replacements of direct access with a helper function indicate index
"0".
* tests/* - only 3 of these are new files added explicitly to test the
new <listen> element. All the others have been modified to reflect
the fact that any legacy "listen" attributes passed in to the domain
parse will be saved in a <listen> element (i.e. one of the
virDomainGraphicsListenDefs), and during the domain format function,
both the <listen> element as well as the legacy attributes will be
output.
2011-07-07 04:20:28 +00:00
|
|
|
const char *oldListenAddr, *newListenAddr;
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
const char *oldListenNetwork, *newListenNetwork;
|
2010-12-16 16:10:54 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!olddev) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot find existing graphics device to modify"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
conf: add <listen> subelement to domain <graphics> element
Once it's plugged in, the <listen> element will be an optional
replacement for the "listen" attribute that graphics elements already
have. If the <listen> element is type='address', it will have an
attribute called 'address' which will contain an IP address or dns
name that the guest's display server should listen on. If, however,
type='network', the <listen> element should have an attribute called
'network' that will be set to the name of a network configuration to
get the IP address from.
* docs/schemas/domain.rng: updated to allow the <listen> element
* docs/formatdomain.html.in: document the <listen> element and its
attributes.
* src/conf/domain_conf.[hc]:
1) The domain parser, formatter, and data structure are modified to
support 0 or more <listen> subelements to each <graphics>
element. The old style "legacy" listen attribute is also still
accepted, and will be stored internally just as if it were a
separate <listen> element. On output (i.e. format), the address
attribute of the first <listen> element of type 'address' will be
duplicated in the legacy "listen" attribute of the <graphic>
element.
2) The "listenAddr" attribute has been removed from the unions in
virDomainGRaphicsDef for graphics types vnc, rdp, and spice.
This attribute is now in the <listen> subelement (aka
virDomainGraphicsListenDef)
3) Helper functions were written to provide simple access
(both Get and Set) to the listen elements and their attributes.
* src/libvirt_private.syms: export the listen helper functions
* src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c,
src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c
Modify all these files to use the listen helper functions rather
than directly referencing the (now missing) listenAddr
attribute. There can be multiple <listen> elements to a single
<graphics>, but the drivers all currently only support one, so all
replacements of direct access with a helper function indicate index
"0".
* tests/* - only 3 of these are new files added explicitly to test the
new <listen> element. All the others have been modified to reflect
the fact that any legacy "listen" attributes passed in to the domain
parse will be saved in a <listen> element (i.e. one of the
virDomainGraphicsListenDefs), and during the domain format function,
both the <listen> element as well as the legacy attributes will be
output.
2011-07-07 04:20:28 +00:00
|
|
|
oldListenAddr = virDomainGraphicsListenGetAddress(olddev, 0);
|
|
|
|
newListenAddr = virDomainGraphicsListenGetAddress(dev, 0);
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
oldListenNetwork = virDomainGraphicsListenGetNetwork(olddev, 0);
|
|
|
|
newListenNetwork = virDomainGraphicsListenGetNetwork(dev, 0);
|
conf: add <listen> subelement to domain <graphics> element
Once it's plugged in, the <listen> element will be an optional
replacement for the "listen" attribute that graphics elements already
have. If the <listen> element is type='address', it will have an
attribute called 'address' which will contain an IP address or dns
name that the guest's display server should listen on. If, however,
type='network', the <listen> element should have an attribute called
'network' that will be set to the name of a network configuration to
get the IP address from.
* docs/schemas/domain.rng: updated to allow the <listen> element
* docs/formatdomain.html.in: document the <listen> element and its
attributes.
* src/conf/domain_conf.[hc]:
1) The domain parser, formatter, and data structure are modified to
support 0 or more <listen> subelements to each <graphics>
element. The old style "legacy" listen attribute is also still
accepted, and will be stored internally just as if it were a
separate <listen> element. On output (i.e. format), the address
attribute of the first <listen> element of type 'address' will be
duplicated in the legacy "listen" attribute of the <graphic>
element.
2) The "listenAddr" attribute has been removed from the unions in
virDomainGRaphicsDef for graphics types vnc, rdp, and spice.
This attribute is now in the <listen> subelement (aka
virDomainGraphicsListenDef)
3) Helper functions were written to provide simple access
(both Get and Set) to the listen elements and their attributes.
* src/libvirt_private.syms: export the listen helper functions
* src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c,
src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c
Modify all these files to use the listen helper functions rather
than directly referencing the (now missing) listenAddr
attribute. There can be multiple <listen> elements to a single
<graphics>, but the drivers all currently only support one, so all
replacements of direct access with a helper function indicate index
"0".
* tests/* - only 3 of these are new files added explicitly to test the
new <listen> element. All the others have been modified to reflect
the fact that any legacy "listen" attributes passed in to the domain
parse will be saved in a <listen> element (i.e. one of the
virDomainGraphicsListenDefs), and during the domain format function,
both the <listen> element as well as the legacy attributes will be
output.
2011-07-07 04:20:28 +00:00
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
switch (dev->type) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
|
|
|
|
if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
|
2011-06-06 19:35:41 +00:00
|
|
|
(!dev->data.vnc.autoport &&
|
|
|
|
(olddev->data.vnc.port != dev->data.vnc.port))) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change port settings on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
conf: add <listen> subelement to domain <graphics> element
Once it's plugged in, the <listen> element will be an optional
replacement for the "listen" attribute that graphics elements already
have. If the <listen> element is type='address', it will have an
attribute called 'address' which will contain an IP address or dns
name that the guest's display server should listen on. If, however,
type='network', the <listen> element should have an attribute called
'network' that will be set to the name of a network configuration to
get the IP address from.
* docs/schemas/domain.rng: updated to allow the <listen> element
* docs/formatdomain.html.in: document the <listen> element and its
attributes.
* src/conf/domain_conf.[hc]:
1) The domain parser, formatter, and data structure are modified to
support 0 or more <listen> subelements to each <graphics>
element. The old style "legacy" listen attribute is also still
accepted, and will be stored internally just as if it were a
separate <listen> element. On output (i.e. format), the address
attribute of the first <listen> element of type 'address' will be
duplicated in the legacy "listen" attribute of the <graphic>
element.
2) The "listenAddr" attribute has been removed from the unions in
virDomainGRaphicsDef for graphics types vnc, rdp, and spice.
This attribute is now in the <listen> subelement (aka
virDomainGraphicsListenDef)
3) Helper functions were written to provide simple access
(both Get and Set) to the listen elements and their attributes.
* src/libvirt_private.syms: export the listen helper functions
* src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c,
src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c
Modify all these files to use the listen helper functions rather
than directly referencing the (now missing) listenAddr
attribute. There can be multiple <listen> elements to a single
<graphics>, but the drivers all currently only support one, so all
replacements of direct access with a helper function indicate index
"0".
* tests/* - only 3 of these are new files added explicitly to test the
new <listen> element. All the others have been modified to reflect
the fact that any legacy "listen" attributes passed in to the domain
parse will be saved in a <listen> element (i.e. one of the
virDomainGraphicsListenDefs), and during the domain format function,
both the <listen> element as well as the legacy attributes will be
output.
2011-07-07 04:20:28 +00:00
|
|
|
if (STRNEQ_NULLABLE(oldListenAddr,newListenAddr)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change listen address setting on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
if (STRNEQ_NULLABLE(oldListenNetwork,newListenNetwork)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change listen network setting on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change keymap setting on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-05-26 14:15:54 +00:00
|
|
|
/* If a password lifetime was, or is set, or action if connected has
|
|
|
|
* changed, then we must always run, even if new password matches
|
|
|
|
* old password */
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
if (olddev->data.vnc.auth.expires ||
|
|
|
|
dev->data.vnc.auth.expires ||
|
2011-05-26 14:15:54 +00:00
|
|
|
olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
|
2011-06-06 19:35:41 +00:00
|
|
|
STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
|
|
|
|
dev->data.vnc.auth.passwd)) {
|
|
|
|
VIR_DEBUG("Updating password on VNC server %p %p",
|
|
|
|
dev->data.vnc.auth.passwd, driver->vncPassword);
|
|
|
|
ret = qemuDomainChangeGraphicsPasswords(driver, vm,
|
|
|
|
VIR_DOMAIN_GRAPHICS_TYPE_VNC,
|
|
|
|
&dev->data.vnc.auth,
|
|
|
|
driver->vncPassword);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
/* Steal the new dev's char * reference */
|
|
|
|
VIR_FREE(olddev->data.vnc.auth.passwd);
|
|
|
|
olddev->data.vnc.auth.passwd = dev->data.vnc.auth.passwd;
|
|
|
|
dev->data.vnc.auth.passwd = NULL;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
|
|
|
|
olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
|
2011-05-26 14:15:54 +00:00
|
|
|
olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
|
2010-12-16 16:10:54 +00:00
|
|
|
} else {
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
|
|
|
|
if ((olddev->data.spice.autoport != dev->data.spice.autoport) ||
|
2011-06-06 19:35:41 +00:00
|
|
|
(!dev->data.spice.autoport &&
|
|
|
|
(olddev->data.spice.port != dev->data.spice.port)) ||
|
|
|
|
(!dev->data.spice.autoport &&
|
|
|
|
(olddev->data.spice.tlsPort != dev->data.spice.tlsPort))) {
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change port settings on spice graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
conf: add <listen> subelement to domain <graphics> element
Once it's plugged in, the <listen> element will be an optional
replacement for the "listen" attribute that graphics elements already
have. If the <listen> element is type='address', it will have an
attribute called 'address' which will contain an IP address or dns
name that the guest's display server should listen on. If, however,
type='network', the <listen> element should have an attribute called
'network' that will be set to the name of a network configuration to
get the IP address from.
* docs/schemas/domain.rng: updated to allow the <listen> element
* docs/formatdomain.html.in: document the <listen> element and its
attributes.
* src/conf/domain_conf.[hc]:
1) The domain parser, formatter, and data structure are modified to
support 0 or more <listen> subelements to each <graphics>
element. The old style "legacy" listen attribute is also still
accepted, and will be stored internally just as if it were a
separate <listen> element. On output (i.e. format), the address
attribute of the first <listen> element of type 'address' will be
duplicated in the legacy "listen" attribute of the <graphic>
element.
2) The "listenAddr" attribute has been removed from the unions in
virDomainGRaphicsDef for graphics types vnc, rdp, and spice.
This attribute is now in the <listen> subelement (aka
virDomainGraphicsListenDef)
3) Helper functions were written to provide simple access
(both Get and Set) to the listen elements and their attributes.
* src/libvirt_private.syms: export the listen helper functions
* src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c,
src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c
Modify all these files to use the listen helper functions rather
than directly referencing the (now missing) listenAddr
attribute. There can be multiple <listen> elements to a single
<graphics>, but the drivers all currently only support one, so all
replacements of direct access with a helper function indicate index
"0".
* tests/* - only 3 of these are new files added explicitly to test the
new <listen> element. All the others have been modified to reflect
the fact that any legacy "listen" attributes passed in to the domain
parse will be saved in a <listen> element (i.e. one of the
virDomainGraphicsListenDefs), and during the domain format function,
both the <listen> element as well as the legacy attributes will be
output.
2011-07-07 04:20:28 +00:00
|
|
|
if (STRNEQ_NULLABLE(oldListenAddr, newListenAddr)) {
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change listen address setting on spice graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
if (STRNEQ_NULLABLE(oldListenNetwork,newListenNetwork)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-09-29 13:00:20 +00:00
|
|
|
_("cannot change listen network setting on spice graphics"));
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2011-06-06 19:35:41 +00:00
|
|
|
if (STRNEQ_NULLABLE(olddev->data.spice.keymap,
|
|
|
|
dev->data.spice.keymap)) {
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change keymap setting on spice graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If a password lifetime was, or is set, then we must always run,
|
|
|
|
* even if new password matches old password */
|
|
|
|
if (olddev->data.spice.auth.expires ||
|
|
|
|
dev->data.spice.auth.expires ||
|
2011-05-26 14:15:54 +00:00
|
|
|
olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
|
2011-06-06 19:35:41 +00:00
|
|
|
STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
|
|
|
|
dev->data.spice.auth.passwd)) {
|
|
|
|
VIR_DEBUG("Updating password on SPICE server %p %p",
|
|
|
|
dev->data.spice.auth.passwd, driver->spicePassword);
|
|
|
|
ret = qemuDomainChangeGraphicsPasswords(driver, vm,
|
|
|
|
VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
|
|
|
|
&dev->data.spice.auth,
|
|
|
|
driver->spicePassword);
|
|
|
|
|
|
|
|
/* Steal the new dev's char * reference */
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
VIR_FREE(olddev->data.spice.auth.passwd);
|
|
|
|
olddev->data.spice.auth.passwd = dev->data.spice.auth.passwd;
|
|
|
|
dev->data.spice.auth.passwd = NULL;
|
|
|
|
olddev->data.spice.auth.validTo = dev->data.spice.auth.validTo;
|
|
|
|
olddev->data.spice.auth.expires = dev->data.spice.auth.expires;
|
2011-05-26 14:15:54 +00:00
|
|
|
olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
} else {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_DEBUG("Not updating since password didn't change");
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
ret = 0;
|
|
|
|
}
|
2011-06-06 19:30:52 +00:00
|
|
|
break;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to change config on '%s' graphics type"),
|
|
|
|
virDomainGraphicsTypeToString(dev->type));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int qemuFindDisk(virDomainDefPtr def, const char *dst)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
if (STREQ(def->disks[i]->dst, dst)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-05-09 06:59:16 +00:00
|
|
|
static int qemuComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
2012-02-22 21:06:10 +00:00
|
|
|
virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
|
2012-02-23 17:59:21 +00:00
|
|
|
virDomainDeviceInfoPtr info1,
|
2011-05-09 06:59:16 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
2012-02-23 17:59:21 +00:00
|
|
|
virDomainDeviceInfoPtr info2 = opaque;
|
2011-05-09 06:59:16 +00:00
|
|
|
|
2012-02-23 17:59:21 +00:00
|
|
|
if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
|
|
|
|
info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
|
2011-05-09 06:59:16 +00:00
|
|
|
return 0;
|
|
|
|
|
2012-02-23 17:59:21 +00:00
|
|
|
if (info1->addr.pci.slot == info2->addr.pci.slot &&
|
|
|
|
info1->addr.pci.function != info2->addr.pci.function)
|
2011-05-09 06:59:16 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
if (virDomainDeviceInfoIterate(def, qemuComparePCIDevice, dev) < 0)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
int qemuDomainDetachPciDiskDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainDiskDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
|
|
|
|
i = qemuFindDisk(vm->def, dev->data.disk->dst);
|
|
|
|
|
|
|
|
if (i < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk %s not found"), dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach = vm->def->disks[i];
|
|
|
|
|
2011-05-09 06:59:16 +00:00
|
|
|
if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("cannot hot unplug multifunction PCI device: %s"),
|
|
|
|
dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-01-28 03:39:44 +00:00
|
|
|
_("Unable to find cgroup for %s"),
|
2010-12-16 16:10:54 +00:00
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("device cannot be detached without a PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build the actual drive id string as the disk->info.alias doesn't
|
|
|
|
* contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
|
|
|
|
if (virAsprintf(&drivestr, "%s%s",
|
|
|
|
QEMU_DRIVE_HOST_PREFIX, detach->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
2011-07-04 14:35:03 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
2011-07-04 14:35:03 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect guest from host device */
|
|
|
|
qemuMonitorDriveDel(priv->mon, drivestr);
|
|
|
|
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, detach->src, NULL, "detach", true);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2011-05-23 07:43:35 +00:00
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
|
|
|
detach->info.addr.pci.slot) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to release PCI address on %s", dev->data.disk->src);
|
|
|
|
|
|
|
|
virDomainDiskRemove(vm->def, i);
|
|
|
|
|
|
|
|
virDomainDiskDefFree(detach);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, dev->data.disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
|
|
|
|
|
|
|
if (cgroup != NULL) {
|
2011-02-16 02:18:40 +00:00
|
|
|
if (qemuTeardownDiskCgroup(driver, vm, cgroup, dev->data.disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
|
|
|
NULLSTR(dev->data.disk->src));
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, dev->data.disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on %s", dev->data.disk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2012-03-15 10:47:13 +00:00
|
|
|
virCgroupFree(&cgroup);
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_FREE(drivestr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-03-07 03:31:48 +00:00
|
|
|
int qemuDomainDetachDiskDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainDiskDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
|
|
|
|
i = qemuFindDisk(vm->def, dev->data.disk->dst);
|
|
|
|
|
|
|
|
if (i < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk %s not found"), dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2011-03-07 03:31:48 +00:00
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("Underlying qemu does not support %s disk removal"),
|
|
|
|
virDomainDiskBusTypeToString(dev->data.disk->bus));
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach = vm->def->disks[i];
|
|
|
|
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-01-28 03:39:44 +00:00
|
|
|
_("Unable to find cgroup for %s"),
|
2010-12-16 16:10:54 +00:00
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build the actual drive id string as the disk->info.alias doesn't
|
|
|
|
* contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
|
|
|
|
if (virAsprintf(&drivestr, "%s%s",
|
|
|
|
QEMU_DRIVE_HOST_PREFIX, detach->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
2011-07-04 14:35:03 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect guest from host device */
|
|
|
|
qemuMonitorDriveDel(priv->mon, drivestr);
|
|
|
|
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
2011-08-22 19:49:10 +00:00
|
|
|
virDomainAuditDisk(vm, detach->src, NULL, "detach", true);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
virDomainDiskRemove(vm->def, i);
|
|
|
|
|
|
|
|
virDomainDiskDefFree(detach);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
Change security driver APIs to use virDomainDefPtr instead of virDomainObjPtr
When sVirt is integrated with the LXC driver, it will be neccessary
to invoke the security driver APIs using only a virDomainDefPtr
since the lxc_container.c code has no virDomainObjPtr available.
Aside from two functions which want obj->pid, every bit of the
security driver code only touches obj->def. So we don't need to
pass a virDomainObjPtr into the security drivers, a virDomainDefPtr
is sufficient. Two functions also gain a 'pid_t pid' argument.
* src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/security/security_apparmor.c,
src/security/security_dac.c,
src/security/security_driver.h,
src/security/security_manager.c,
src/security/security_manager.h,
src/security/security_nop.c,
src/security/security_selinux.c,
src/security/security_stack.c: Change all security APIs to use a
virDomainDefPtr instead of virDomainObjPtr
2011-07-14 13:32:06 +00:00
|
|
|
vm->def, dev->data.disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
|
|
|
|
|
|
|
if (cgroup != NULL) {
|
2011-02-16 02:18:40 +00:00
|
|
|
if (qemuTeardownDiskCgroup(driver, vm, cgroup, dev->data.disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
|
|
|
NULLSTR(dev->data.disk->src));
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (virDomainLockDiskDetach(driver->lockManager, vm, dev->data.disk) < 0)
|
|
|
|
VIR_WARN("Unable to release lock on disk %s", dev->data.disk->src);
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-02-21 07:35:52 +00:00
|
|
|
static bool qemuDomainDiskControllerIsBusy(virDomainObjPtr vm,
|
|
|
|
virDomainControllerDefPtr detach)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
virDomainDiskDefPtr disk;
|
|
|
|
|
|
|
|
for (i = 0; i < vm->def->ndisks; i++) {
|
|
|
|
disk = vm->def->disks[i];
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
|
|
|
|
/* the disk does not use disk controller */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* check whether the disk uses this type controller */
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE &&
|
|
|
|
detach->type != VIR_DOMAIN_CONTROLLER_TYPE_IDE)
|
|
|
|
continue;
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC &&
|
|
|
|
detach->type != VIR_DOMAIN_CONTROLLER_TYPE_FDC)
|
|
|
|
continue;
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
|
|
|
|
detach->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (disk->info.addr.drive.controller == detach->idx)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool qemuDomainControllerIsBusy(virDomainObjPtr vm,
|
|
|
|
virDomainControllerDefPtr detach)
|
|
|
|
{
|
|
|
|
switch (detach->type) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
|
|
|
|
return qemuDomainDiskControllerIsBusy(vm, detach);
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
|
|
|
|
default:
|
|
|
|
/* libvirt does not support sata controller, and does not support to
|
|
|
|
* detach virtio and smart card controller.
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2011-05-04 12:09:09 +00:00
|
|
|
virDomainDeviceDefPtr dev)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainControllerDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ncontrollers ; i++) {
|
|
|
|
if ((vm->def->controllers[i]->type == dev->data.controller->type) &&
|
|
|
|
(vm->def->controllers[i]->idx == dev->data.controller->idx)) {
|
|
|
|
detach = vm->def->controllers[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk controller %s:%d not found"),
|
|
|
|
virDomainControllerTypeToString(dev->data.controller->type),
|
|
|
|
dev->data.controller->idx);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("device cannot be detached without a PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-09 06:59:16 +00:00
|
|
|
if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("cannot hot unplug multifunction PCI device: %s"),
|
|
|
|
dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-02-21 07:35:52 +00:00
|
|
|
if (qemuDomainControllerIsBusy(vm, detach)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("device cannot be detached: device is busy"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuAssignDeviceControllerAlias(detach) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) {
|
2011-07-04 14:35:03 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
2011-07-04 14:35:03 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
2010-12-16 16:10:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
if (vm->def->ncontrollers > 1) {
|
|
|
|
memmove(vm->def->controllers + i,
|
|
|
|
vm->def->controllers + i + 1,
|
|
|
|
sizeof(*vm->def->controllers) *
|
|
|
|
(vm->def->ncontrollers - (i + 1)));
|
|
|
|
vm->def->ncontrollers--;
|
|
|
|
if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers) < 0) {
|
|
|
|
/* ignore, harmless */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VIR_FREE(vm->def->controllers);
|
|
|
|
vm->def->ncontrollers = 0;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2011-05-23 07:43:35 +00:00
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
|
|
|
detach->info.addr.pci.slot) < 0)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Unable to release PCI address on controller");
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
virDomainControllerDefFree(detach);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-15 16:51:56 +00:00
|
|
|
static int
|
|
|
|
qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2012-03-07 01:43:22 +00:00
|
|
|
virDomainHostdevDefPtr detach)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2012-02-27 11:53:19 +00:00
|
|
|
virDomainHostdevSubsysPtr subsys = &detach->source.subsys;
|
|
|
|
int ret;
|
2010-12-16 16:10:54 +00:00
|
|
|
pciDevice *pci;
|
2011-11-29 10:09:24 +00:00
|
|
|
pciDevice *activePci;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (qemuIsMultiFunctionDevice(vm->def, detach->info)) {
|
2011-05-09 06:59:16 +00:00
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
2012-02-27 11:53:19 +00:00
|
|
|
_("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
|
|
|
|
subsys->u.pci.domain, subsys->u.pci.bus,
|
|
|
|
subsys->u.pci.slot, subsys->u.pci.function);
|
2011-05-09 06:59:16 +00:00
|
|
|
return -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (!virDomainDeviceAddressIsValid(detach->info,
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached without a PCI address"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2012-01-31 09:16:54 +00:00
|
|
|
ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
|
2010-12-16 16:10:54 +00:00
|
|
|
} else {
|
2012-01-31 09:16:54 +00:00
|
|
|
ret = qemuMonitorRemovePCIDevice(priv->mon, &detach->info->addr.pci);
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditHostdev(vm, detach, "detach", ret == 0);
|
2011-02-23 23:15:23 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-03-06 01:12:44 +00:00
|
|
|
/*
|
|
|
|
* For SRIOV net host devices, unset mac and port profile before
|
|
|
|
* reset and reattach device
|
|
|
|
*/
|
|
|
|
if (detach->parent.data.net)
|
|
|
|
qemuDomainHostdevNetConfigRestore(detach, driver->stateDir);
|
|
|
|
|
2012-02-27 11:53:19 +00:00
|
|
|
pci = pciGetDevice(subsys->u.pci.domain, subsys->u.pci.bus,
|
|
|
|
subsys->u.pci.slot, subsys->u.pci.function);
|
2011-11-29 10:09:24 +00:00
|
|
|
if (pci) {
|
|
|
|
activePci = pciDeviceListSteal(driver->activePciHostdevs, pci);
|
2012-05-21 14:31:53 +00:00
|
|
|
if (activePci &&
|
|
|
|
pciResetDevice(activePci, driver->activePciHostdevs,
|
|
|
|
driver->inactivePciHostdevs) == 0) {
|
2011-11-29 10:09:24 +00:00
|
|
|
qemuReattachPciDevice(activePci, driver);
|
2012-05-21 14:31:53 +00:00
|
|
|
} else {
|
|
|
|
/* reset of the device failed, treat it as if it was returned */
|
|
|
|
pciFreeDevice(activePci);
|
2010-12-16 16:10:54 +00:00
|
|
|
ret = -1;
|
2012-05-21 14:31:53 +00:00
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
pciFreeDevice(pci);
|
2011-11-29 10:09:24 +00:00
|
|
|
} else {
|
|
|
|
ret = -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
2011-05-23 07:43:35 +00:00
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
2012-01-31 09:16:54 +00:00
|
|
|
detach->info->addr.pci.slot) < 0)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Unable to release PCI address on host device");
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-15 16:51:56 +00:00
|
|
|
static int
|
|
|
|
qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
2012-03-07 01:43:22 +00:00
|
|
|
virDomainHostdevDefPtr detach)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2012-02-27 11:53:19 +00:00
|
|
|
virDomainHostdevSubsysPtr subsys = &detach->source.subsys;
|
2011-12-21 17:58:29 +00:00
|
|
|
usbDevice *usb;
|
2012-02-27 11:53:19 +00:00
|
|
|
int ret;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (!detach->info->alias) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached without a device alias"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-05-04 12:09:09 +00:00
|
|
|
if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached with this QEMU version"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
2012-01-31 09:16:54 +00:00
|
|
|
ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
virDomainAuditHostdev(vm, detach, "detach", ret == 0);
|
2011-02-23 23:15:23 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-02-27 11:53:19 +00:00
|
|
|
usb = usbGetDevice(subsys->u.usb.bus, subsys->u.usb.device);
|
2011-12-21 17:58:29 +00:00
|
|
|
if (usb) {
|
|
|
|
usbDeviceListDel(driver->activeUsbHostdevs, usb);
|
|
|
|
usbFreeDevice(usb);
|
|
|
|
} else {
|
|
|
|
VIR_WARN("Unable to find device %03d.%03d in list of used USB devices",
|
2012-02-27 11:53:19 +00:00
|
|
|
subsys->u.usb.bus, subsys->u.usb.device);
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-02-27 11:53:19 +00:00
|
|
|
static
|
|
|
|
int qemuDomainDetachThisHostDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainHostdevDefPtr detach,
|
|
|
|
int idx)
|
2010-12-16 16:10:54 +00:00
|
|
|
{
|
2012-02-27 11:53:19 +00:00
|
|
|
int ret = -1;
|
2010-12-16 16:10:54 +00:00
|
|
|
|
2012-02-27 11:53:19 +00:00
|
|
|
if (idx < 0) {
|
|
|
|
/* caller didn't know index of hostdev in hostdevs list, so we
|
|
|
|
* need to find it.
|
|
|
|
*/
|
|
|
|
for (idx = 0; idx < vm->def->nhostdevs; idx++) {
|
|
|
|
if (vm->def->hostdevs[idx] == detach)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (idx >= vm->def->nhostdevs) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("device not found in hostdevs list (%d entries)"),
|
|
|
|
vm->def->nhostdevs);
|
|
|
|
return ret;
|
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
}
|
|
|
|
|
2012-02-27 11:53:19 +00:00
|
|
|
switch (detach->source.subsys.type) {
|
2010-12-16 16:10:54 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
2012-03-07 01:43:22 +00:00
|
|
|
ret = qemuDomainDetachHostPciDevice(driver, vm, detach);
|
|
|
|
break;
|
2010-12-16 16:10:54 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
2012-03-07 01:43:22 +00:00
|
|
|
ret = qemuDomainDetachHostUsbDevice(driver, vm, detach);
|
2010-12-16 16:10:54 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev subsys type '%s' not supported"),
|
2012-02-27 11:53:19 +00:00
|
|
|
virDomainHostdevSubsysTypeToString(detach->source.subsys.type));
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-07 01:43:22 +00:00
|
|
|
if (!ret) {
|
|
|
|
if (virSecurityManagerRestoreHostdevLabel(driver->securityManager,
|
|
|
|
vm->def, detach) < 0) {
|
|
|
|
VIR_WARN("Failed to restore host device labelling");
|
|
|
|
}
|
|
|
|
virDomainHostdevRemove(vm->def, idx);
|
|
|
|
virDomainHostdevDefFree(detach);
|
2012-02-27 11:53:19 +00:00
|
|
|
}
|
2010-12-16 16:10:54 +00:00
|
|
|
return ret;
|
|
|
|
}
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
|
2012-02-27 11:53:19 +00:00
|
|
|
/* search for a hostdev matching dev and detach it */
|
|
|
|
int qemuDomainDetachHostDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
virDomainHostdevDefPtr hostdev = dev->data.hostdev;
|
|
|
|
virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
|
|
|
|
virDomainHostdevDefPtr detach = NULL;
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev mode '%s' not supported"),
|
|
|
|
virDomainHostdevModeTypeToString(hostdev->mode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
idx = virDomainHostdevFind(vm->def, hostdev, &detach);
|
|
|
|
|
|
|
|
if (idx < 0) {
|
|
|
|
switch(subsys->type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("host pci device %.4x:%.2x:%.2x.%.1x not found"),
|
|
|
|
subsys->u.pci.domain, subsys->u.pci.bus,
|
|
|
|
subsys->u.pci.slot, subsys->u.pci.function);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
|
|
if (subsys->u.usb.bus && subsys->u.usb.device) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("host usb device %03d.%03d not found"),
|
|
|
|
subsys->u.usb.bus, subsys->u.usb.device);
|
|
|
|
} else {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("host usb device vendor=0x%.4x product=0x%.4x not found"),
|
|
|
|
subsys->u.usb.vendor, subsys->u.usb.product);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected hostdev type %d"), subsys->type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
qemu: support type=hostdev network device live hotplug attach/detach
qemuDomainAttachNetDevice
- re-ordered some things at start of function because
networkAllocateActualDevice should always be run and a slot
in def->nets always allocated, but host_net_add isn't needed
if the actual type is hostdev.
- if actual type is hostdev, defer to
qemuDomainAttachHostDevice (which will reach up to the NetDef
for things like MAC address when necessary). After return
from qemuDomainAttachHostDevice, slip directly to cleanup,
since the rest of the function is specific to emulated net
devices.
- put assignment of new NetDef into expanded def->nets down
below cleanup: (but only on success) since it is also needed
for emulated and hostdev net devices.
qemuDomainDetachHostDevice
- after locating the exact device to detach, check if it's a
network device and, if so, use toplevel
qemuDomainDetachNetDevice instead so that the def->nets list
is properly updated, and 'actual device' properly returned to
network pool if appropriate. Otherwise, for normal hostdevs,
call the lower level qemuDomainDetachThisDevice.
qemuDomainDetachNetDevice
- This is where it gets a bit tricky. After locating the device
on the def->nets list, if the network device type == hostdev,
call the *lower level* qemuDomainDetachThisDevice (which will
reach back up to the parent net device for MAC address /
virtualport when appropriate, then clear the device out of
def->hostdevs) before skipping past all the emulated
net-device-specific code to cleanup:, where the network
device is removed from def->nets, and the network device
object is freed.
In short, any time a hostdev-type network device is detached, we must
go through the toplevel virDomaineDetachNetDevice function first and
last, to make sure 1) the def->nnets list is properly managed, and 2)
any device allocated with networkAllocateActualDevice is properly
freed. At the same time, in the middle we need to go through the
lower-level vidDomainDetach*This*HostDevice to be sure that 1) the
def->hostdevs list is properly managed, 2) the PCI device is properly
detached from the guest and reattached to the host (if appropriate),
and 3) any higher level teardown is called at the appropriate time, by
reaching back up to the NetDef config (part (3) will be covered in a
separate patch).
2012-02-27 19:20:17 +00:00
|
|
|
/* If this is a network hostdev, we need to use the higher-level detach
|
|
|
|
* function so that mac address / virtualport are reset
|
|
|
|
*/
|
|
|
|
if (detach->parent.type == VIR_DOMAIN_DEVICE_NET)
|
|
|
|
return qemuDomainDetachNetDevice(driver, vm, &detach->parent);
|
|
|
|
else
|
|
|
|
return qemuDomainDetachThisHostDevice(driver, vm, detach, idx);
|
2012-02-27 11:53:19 +00:00
|
|
|
}
|
|
|
|
|
2012-02-27 12:03:12 +00:00
|
|
|
int
|
|
|
|
qemuDomainDetachNetDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev)
|
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainNetDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int vlan;
|
|
|
|
char *hostnet_name = NULL;
|
|
|
|
virNetDevVPortProfilePtr vport = NULL;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->nnets ; i++) {
|
|
|
|
virDomainNetDefPtr net = vm->def->nets[i];
|
|
|
|
|
|
|
|
if (!memcmp(net->mac, dev->data.net->mac, sizeof(net->mac))) {
|
|
|
|
detach = net;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("network device %02x:%02x:%02x:%02x:%02x:%02x not found"),
|
|
|
|
dev->data.net->mac[0], dev->data.net->mac[1],
|
|
|
|
dev->data.net->mac[2], dev->data.net->mac[3],
|
|
|
|
dev->data.net->mac[4], dev->data.net->mac[5]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-03-12 15:50:02 +00:00
|
|
|
if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
|
ret = qemuDomainDetachThisHostDevice(driver, vm,
|
|
|
|
virDomainNetGetActualHostdev(detach),
|
|
|
|
-1);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-02-27 12:03:12 +00:00
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached without a PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("cannot hot unplug multifunction PCI device :%s"),
|
|
|
|
dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("unable to determine original VLAN"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
virDomainAuditNet(vm, detach, NULL, "detach", true);
|
|
|
|
|
|
|
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
|
|
|
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
|
|
|
detach->info.addr.pci.slot) < 0)
|
|
|
|
VIR_WARN("Unable to release PCI address on NIC");
|
|
|
|
|
|
|
|
virDomainConfNWFilterTeardown(detach);
|
|
|
|
|
|
|
|
if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
|
ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
|
|
|
|
detach->ifname, detach->mac,
|
|
|
|
virDomainNetGetActualDirectDev(detach),
|
|
|
|
virDomainNetGetActualDirectMode(detach),
|
|
|
|
virDomainNetGetActualVirtPortProfile(detach),
|
|
|
|
driver->stateDir));
|
|
|
|
VIR_FREE(detach->ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((driver->macFilter) && (detach->ifname != NULL)) {
|
|
|
|
if ((errno = networkDisallowMacOnPort(driver,
|
|
|
|
detach->ifname,
|
|
|
|
detach->mac))) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("failed to remove ebtables rule on '%s'"),
|
|
|
|
detach->ifname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vport = virDomainNetGetActualVirtPortProfile(detach);
|
|
|
|
if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
|
|
|
|
ignore_value(virNetDevOpenvswitchRemovePort(
|
|
|
|
virDomainNetGetActualBridgeName(detach),
|
|
|
|
detach->ifname));
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
qemu: support type=hostdev network device live hotplug attach/detach
qemuDomainAttachNetDevice
- re-ordered some things at start of function because
networkAllocateActualDevice should always be run and a slot
in def->nets always allocated, but host_net_add isn't needed
if the actual type is hostdev.
- if actual type is hostdev, defer to
qemuDomainAttachHostDevice (which will reach up to the NetDef
for things like MAC address when necessary). After return
from qemuDomainAttachHostDevice, slip directly to cleanup,
since the rest of the function is specific to emulated net
devices.
- put assignment of new NetDef into expanded def->nets down
below cleanup: (but only on success) since it is also needed
for emulated and hostdev net devices.
qemuDomainDetachHostDevice
- after locating the exact device to detach, check if it's a
network device and, if so, use toplevel
qemuDomainDetachNetDevice instead so that the def->nets list
is properly updated, and 'actual device' properly returned to
network pool if appropriate. Otherwise, for normal hostdevs,
call the lower level qemuDomainDetachThisDevice.
qemuDomainDetachNetDevice
- This is where it gets a bit tricky. After locating the device
on the def->nets list, if the network device type == hostdev,
call the *lower level* qemuDomainDetachThisDevice (which will
reach back up to the parent net device for MAC address /
virtualport when appropriate, then clear the device out of
def->hostdevs) before skipping past all the emulated
net-device-specific code to cleanup:, where the network
device is removed from def->nets, and the network device
object is freed.
In short, any time a hostdev-type network device is detached, we must
go through the toplevel virDomaineDetachNetDevice function first and
last, to make sure 1) the def->nnets list is properly managed, and 2)
any device allocated with networkAllocateActualDevice is properly
freed. At the same time, in the middle we need to go through the
lower-level vidDomainDetach*This*HostDevice to be sure that 1) the
def->hostdevs list is properly managed, 2) the PCI device is properly
detached from the guest and reattached to the host (if appropriate),
and 3) any higher level teardown is called at the appropriate time, by
reaching back up to the NetDef config (part (3) will be covered in a
separate patch).
2012-02-27 19:20:17 +00:00
|
|
|
if (!ret) {
|
|
|
|
networkReleaseActualDevice(detach);
|
|
|
|
virDomainNetRemove(vm->def, i);
|
|
|
|
virDomainNetDefFree(detach);
|
|
|
|
}
|
2012-02-27 12:03:12 +00:00
|
|
|
VIR_FREE(hostnet_name);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
int
|
|
|
|
qemuDomainChangeGraphicsPasswords(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
int type,
|
|
|
|
virDomainGraphicsAuthDefPtr auth,
|
|
|
|
const char *defaultPasswd)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
time_t now = time(NULL);
|
|
|
|
char expire_time [64];
|
2011-05-26 14:15:54 +00:00
|
|
|
const char *connected = NULL;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!auth->passwd && !driver->vncPassword)
|
|
|
|
return 0;
|
|
|
|
|
2011-05-26 14:15:54 +00:00
|
|
|
if (auth->connected)
|
|
|
|
connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected);
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
ret = qemuMonitorSetPassword(priv->mon,
|
|
|
|
type,
|
|
|
|
auth->passwd ? auth->passwd : defaultPasswd,
|
2011-05-26 14:15:54 +00:00
|
|
|
connected);
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
|
|
|
|
if (ret == -2) {
|
|
|
|
if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-03-07 18:09:35 +00:00
|
|
|
_("Graphics password only supported for VNC"));
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorSetVNCPassword(priv->mon,
|
|
|
|
auth->passwd ? auth->passwd : defaultPasswd);
|
|
|
|
}
|
|
|
|
}
|
2011-01-18 18:37:45 +00:00
|
|
|
if (ret != 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
if (auth->expires) {
|
|
|
|
time_t lifetime = auth->validTo - now;
|
|
|
|
if (lifetime <= 0)
|
2012-03-29 09:52:04 +00:00
|
|
|
snprintf(expire_time, sizeof(expire_time), "now");
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
else
|
2012-03-29 09:52:04 +00:00
|
|
|
snprintf(expire_time, sizeof(expire_time), "%lu", (long unsigned)auth->validTo);
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
} else {
|
2012-03-29 09:52:04 +00:00
|
|
|
snprintf(expire_time, sizeof(expire_time), "never");
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = qemuMonitorExpirePassword(priv->mon, type, expire_time);
|
|
|
|
|
|
|
|
if (ret == -2) {
|
|
|
|
/* XXX we could fake this with a timer */
|
|
|
|
if (auth->expires) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Expiry of passwords is not supported"));
|
|
|
|
ret = -1;
|
2011-01-18 18:37:45 +00:00
|
|
|
} else {
|
|
|
|
ret = 0;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-18 18:37:45 +00:00
|
|
|
cleanup:
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2011-05-18 16:20:53 +00:00
|
|
|
|
|
|
|
int qemuDomainAttachLease(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainLeaseDefPtr lease)
|
|
|
|
{
|
|
|
|
if (virDomainLeaseInsertPreAlloc(vm->def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virDomainLockLeaseAttach(driver->lockManager, vm, lease) < 0) {
|
|
|
|
virDomainLeaseInsertPreAlloced(vm->def, NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainLeaseInsertPreAlloced(vm->def, lease);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachLease(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainLeaseDefPtr lease)
|
|
|
|
{
|
util: eliminate device object leaks related to virDomain*Remove*()
There are several functions in domain_conf.c that remove a device
object from the domain's list of that object type, but don't free the
object or return it to the caller to free. In many cases this isn't a
problem because the caller already had a pointer to the object and
frees it afterward, but in several cases the removed object was just
left floating around with no references to it.
In particular, the function qemuDomainDetachDeviceConfig() calls
functions to locate and remove net (virDomainNetRemoveByMac), disk
(virDomainDiskRemoveByName()), and lease (virDomainLeaseRemove())
devices, but neither it nor its caller qemuDomainModifyDeviceConfig()
ever obtain a pointer to the device being removed, much less free it.
This patch modifies the following "remove" functions to return a
pointer to the device object being removed from the domain device
arrays, to give the caller the option of freeing the device object
using that pointer if needed. In places where the object was
previously leaked, it is now freed:
virDomainDiskRemove
virDomainDiskRemoveByName
virDomainNetRemove
virDomainNetRemoveByMac
virDomainHostdevRemove
virDomainLeaseRemove
virDomainLeaseRemoveAt
The functions that had been leaking:
libxlDomainDetachConfig - leaked a virDomainDiskDef
qemuDomainDetachDeviceConfig - could leak a virDomainDiskDef,
a virDomainNetDef, or a
virDomainLeaseDef
qemuDomainDetachLease - leaked a virDomainLeaseDef
2012-03-06 23:06:14 +00:00
|
|
|
virDomainLeaseDefPtr det_lease;
|
2011-05-18 16:20:53 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if ((i = virDomainLeaseIndex(vm->def, lease)) < 0) {
|
|
|
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Lease %s in lockspace %s does not exist"),
|
|
|
|
lease->key, NULLSTR(lease->lockspace));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainLockLeaseDetach(driver->lockManager, vm, lease) < 0)
|
|
|
|
return -1;
|
|
|
|
|
util: eliminate device object leaks related to virDomain*Remove*()
There are several functions in domain_conf.c that remove a device
object from the domain's list of that object type, but don't free the
object or return it to the caller to free. In many cases this isn't a
problem because the caller already had a pointer to the object and
frees it afterward, but in several cases the removed object was just
left floating around with no references to it.
In particular, the function qemuDomainDetachDeviceConfig() calls
functions to locate and remove net (virDomainNetRemoveByMac), disk
(virDomainDiskRemoveByName()), and lease (virDomainLeaseRemove())
devices, but neither it nor its caller qemuDomainModifyDeviceConfig()
ever obtain a pointer to the device being removed, much less free it.
This patch modifies the following "remove" functions to return a
pointer to the device object being removed from the domain device
arrays, to give the caller the option of freeing the device object
using that pointer if needed. In places where the object was
previously leaked, it is now freed:
virDomainDiskRemove
virDomainDiskRemoveByName
virDomainNetRemove
virDomainNetRemoveByMac
virDomainHostdevRemove
virDomainLeaseRemove
virDomainLeaseRemoveAt
The functions that had been leaking:
libxlDomainDetachConfig - leaked a virDomainDiskDef
qemuDomainDetachDeviceConfig - could leak a virDomainDiskDef,
a virDomainNetDef, or a
virDomainLeaseDef
qemuDomainDetachLease - leaked a virDomainLeaseDef
2012-03-06 23:06:14 +00:00
|
|
|
det_lease = virDomainLeaseRemoveAt(vm->def, i);
|
|
|
|
virDomainLeaseDefFree(det_lease);
|
2011-05-18 16:20:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|