libvirt/src/vz/vz_utils.c

613 lines
19 KiB
C
Raw Normal View History

/*
* vz_utils.c: core driver functions for managing
* Parallels Cloud Server hosts
*
* Copyright (C) 2012 Parallels, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include <stdarg.h>
#include "vircommand.h"
#include "virerror.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
2012-12-12 17:53:50 +00:00
#include "virjson.h"
#include "vz_utils.h"
vz: fix race condition when adding domain to domains list Race condition: User calls defineXML to create new instance. The main thread from vzDomainDefineXMLFlags() creates new instance by prlsdkCreateVm. Then this thread calls prlsdkAddDomain to add new domain to domains list. The second thread receives notification from hypervisor that new VM was created. It calls prlsdkHandleVmAddedEvent() and also tries to add new domain to domains list. These two threads call virDomainObjListFindByUUID() from prlsdkAddDomain() and don't find new domain. So they add two domains with the same uuid to domains list. This fix splits logic of prlsdkAddDomain() into two functions. 1. vzNewDomain() creates new empty domain in domains list with the specific uuid. 2. prlsdkLoadDomain() add data from VM to domain object. New algorithm for creating an instance: In vzDomainDefineXMLFlags() we add new domain to domain list by calling vzNewDomain() and only after that we call CreateVm() to create VM. It means that we "reserve" domain object with the specific uuid. After creation of new VM we add info from this VM to reserved domain object by calling prlsdkLoadDomain(). Before this patch prlsdkLoadDomain() worked in 2 different cases: 1. It creates and initializes new domain. Then updates it from sdk handle. 2. It updates existed domain from sdk handle. In this patch we remove code which creates new domain from LoadDomain() and move it to vzNewDomain(). Now prlsdkLoadDomain() only updates domain from skd handle. In notification handler prlsdkHandleVmAddedEvent() we check the existence of a domain and if it doesn't exist we add new domain by calling vzNewDomain() and load info from sdk handle via prlsdkLoadDomain().
2016-02-10 09:39:14 +00:00
#include "vz_sdk.h"
#include "virstring.h"
#include "datatypes.h"
#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_PARALLELS
#define PRLSRVCTL "prlsrvctl"
VIR_LOG_INIT("parallels.utils");
static virDomainDiskBus vz6DiskBuses[] = {VIR_DOMAIN_DISK_BUS_IDE,
VIR_DOMAIN_DISK_BUS_SCSI,
VIR_DOMAIN_DISK_BUS_SATA,
VIR_DOMAIN_DISK_BUS_LAST};
static virDomainDiskBus vz7DiskBuses[] = {VIR_DOMAIN_DISK_BUS_IDE,
VIR_DOMAIN_DISK_BUS_SCSI,
VIR_DOMAIN_DISK_BUS_LAST};
static virDomainControllerType vz6ControllerTypes[] = {VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
VIR_DOMAIN_CONTROLLER_TYPE_IDE,
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
VIR_DOMAIN_CONTROLLER_TYPE_LAST};
static virDomainControllerType vz7ControllerTypes[] = {VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
VIR_DOMAIN_CONTROLLER_TYPE_IDE,
VIR_DOMAIN_CONTROLLER_TYPE_LAST};
/**
* vzDomObjFromDomain:
* @domain: Domain pointer that has to be looked up
*
* This function looks up @domain and returns the appropriate virDomainObjPtr
* that has to be unlocked by virObjectUnlock().
*
* Returns the domain object without incremented reference counter which is locked
* on success, NULL otherwise.
*/
virDomainObjPtr
vzDomObjFromDomain(virDomainPtr domain)
{
virDomainObjPtr vm;
vzConnPtr privconn = domain->conn->privateData;
char uuidstr[VIR_UUID_STRING_BUFLEN];
vzDriverPtr driver = privconn->driver;
vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
if (!vm) {
virUUIDFormat(domain->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s' (%s)"),
uuidstr, domain->name);
return NULL;
}
return vm;
}
parallels: add block device statistics to driver Statistics provided through PCS SDK. As we have only async interface in SDK we need to be subscribed to statistics in order to get it. Trivial solution on every stat request to subscribe, wait event and then unsubscribe will lead to significant delays in case of a number of successive requests, as the event will be delivered on next PCS server notify cycle. On the other hand we don't want to keep unnesessary subscribtion. So we take an hibrid solution to subcsribe on first request and then keep a subscription while requests are active. We populate cache of statistics on subscribtion events and use this cache to serve libvirts requests. * Cache details. Cache is just handle to last arrived event, we call this cache as if this handle is valid it is used to serve synchronous statistics requests. We use number of successive events count to detect that user lost interest to statistics. We reset this count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT successive events arrive we unsubscribe. Special value of -1 of this counter is used to differentiate between subscribed/unsubscribed state to protect from delayed events. Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are just drop-ins, choosen without special consideration. * Thread safety issues Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as we could wait on domain lock down on stack in prlsdkGetStatsParam and if we won't keep reference we could get dangling pointer on return from wait. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@parallels.com>
2015-06-09 07:35:53 +00:00
/**
* vzDomObjFromDomainRef:
parallels: add block device statistics to driver Statistics provided through PCS SDK. As we have only async interface in SDK we need to be subscribed to statistics in order to get it. Trivial solution on every stat request to subscribe, wait event and then unsubscribe will lead to significant delays in case of a number of successive requests, as the event will be delivered on next PCS server notify cycle. On the other hand we don't want to keep unnesessary subscribtion. So we take an hibrid solution to subcsribe on first request and then keep a subscription while requests are active. We populate cache of statistics on subscribtion events and use this cache to serve libvirts requests. * Cache details. Cache is just handle to last arrived event, we call this cache as if this handle is valid it is used to serve synchronous statistics requests. We use number of successive events count to detect that user lost interest to statistics. We reset this count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT successive events arrive we unsubscribe. Special value of -1 of this counter is used to differentiate between subscribed/unsubscribed state to protect from delayed events. Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are just drop-ins, choosen without special consideration. * Thread safety issues Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as we could wait on domain lock down on stack in prlsdkGetStatsParam and if we won't keep reference we could get dangling pointer on return from wait. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@parallels.com>
2015-06-09 07:35:53 +00:00
* @domain: Domain pointer that has to be looked up
*
* This function looks up @domain and returns the appropriate virDomainObjPtr
* that has to be released by calling virDomainObjEndAPI().
*
* Returns the domain object with incremented reference counter which is locked
* on success, NULL otherwise.
*/
virDomainObjPtr
vzDomObjFromDomainRef(virDomainPtr domain)
parallels: add block device statistics to driver Statistics provided through PCS SDK. As we have only async interface in SDK we need to be subscribed to statistics in order to get it. Trivial solution on every stat request to subscribe, wait event and then unsubscribe will lead to significant delays in case of a number of successive requests, as the event will be delivered on next PCS server notify cycle. On the other hand we don't want to keep unnesessary subscribtion. So we take an hibrid solution to subcsribe on first request and then keep a subscription while requests are active. We populate cache of statistics on subscribtion events and use this cache to serve libvirts requests. * Cache details. Cache is just handle to last arrived event, we call this cache as if this handle is valid it is used to serve synchronous statistics requests. We use number of successive events count to detect that user lost interest to statistics. We reset this count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT successive events arrive we unsubscribe. Special value of -1 of this counter is used to differentiate between subscribed/unsubscribed state to protect from delayed events. Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are just drop-ins, choosen without special consideration. * Thread safety issues Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as we could wait on domain lock down on stack in prlsdkGetStatsParam and if we won't keep reference we could get dangling pointer on return from wait. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@parallels.com>
2015-06-09 07:35:53 +00:00
{
virDomainObjPtr vm;
vzConnPtr privconn = domain->conn->privateData;
parallels: add block device statistics to driver Statistics provided through PCS SDK. As we have only async interface in SDK we need to be subscribed to statistics in order to get it. Trivial solution on every stat request to subscribe, wait event and then unsubscribe will lead to significant delays in case of a number of successive requests, as the event will be delivered on next PCS server notify cycle. On the other hand we don't want to keep unnesessary subscribtion. So we take an hibrid solution to subcsribe on first request and then keep a subscription while requests are active. We populate cache of statistics on subscribtion events and use this cache to serve libvirts requests. * Cache details. Cache is just handle to last arrived event, we call this cache as if this handle is valid it is used to serve synchronous statistics requests. We use number of successive events count to detect that user lost interest to statistics. We reset this count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT successive events arrive we unsubscribe. Special value of -1 of this counter is used to differentiate between subscribed/unsubscribed state to protect from delayed events. Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are just drop-ins, choosen without special consideration. * Thread safety issues Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as we could wait on domain lock down on stack in prlsdkGetStatsParam and if we won't keep reference we could get dangling pointer on return from wait. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@parallels.com>
2015-06-09 07:35:53 +00:00
char uuidstr[VIR_UUID_STRING_BUFLEN];
vzDriverPtr driver = privconn->driver;
parallels: add block device statistics to driver Statistics provided through PCS SDK. As we have only async interface in SDK we need to be subscribed to statistics in order to get it. Trivial solution on every stat request to subscribe, wait event and then unsubscribe will lead to significant delays in case of a number of successive requests, as the event will be delivered on next PCS server notify cycle. On the other hand we don't want to keep unnesessary subscribtion. So we take an hibrid solution to subcsribe on first request and then keep a subscription while requests are active. We populate cache of statistics on subscribtion events and use this cache to serve libvirts requests. * Cache details. Cache is just handle to last arrived event, we call this cache as if this handle is valid it is used to serve synchronous statistics requests. We use number of successive events count to detect that user lost interest to statistics. We reset this count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT successive events arrive we unsubscribe. Special value of -1 of this counter is used to differentiate between subscribed/unsubscribed state to protect from delayed events. Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are just drop-ins, choosen without special consideration. * Thread safety issues Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as we could wait on domain lock down on stack in prlsdkGetStatsParam and if we won't keep reference we could get dangling pointer on return from wait. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@parallels.com>
2015-06-09 07:35:53 +00:00
vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
parallels: add block device statistics to driver Statistics provided through PCS SDK. As we have only async interface in SDK we need to be subscribed to statistics in order to get it. Trivial solution on every stat request to subscribe, wait event and then unsubscribe will lead to significant delays in case of a number of successive requests, as the event will be delivered on next PCS server notify cycle. On the other hand we don't want to keep unnesessary subscribtion. So we take an hibrid solution to subcsribe on first request and then keep a subscription while requests are active. We populate cache of statistics on subscribtion events and use this cache to serve libvirts requests. * Cache details. Cache is just handle to last arrived event, we call this cache as if this handle is valid it is used to serve synchronous statistics requests. We use number of successive events count to detect that user lost interest to statistics. We reset this count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT successive events arrive we unsubscribe. Special value of -1 of this counter is used to differentiate between subscribed/unsubscribed state to protect from delayed events. Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are just drop-ins, choosen without special consideration. * Thread safety issues Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as we could wait on domain lock down on stack in prlsdkGetStatsParam and if we won't keep reference we could get dangling pointer on return from wait. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@parallels.com>
2015-06-09 07:35:53 +00:00
if (!vm) {
virUUIDFormat(domain->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s' (%s)"),
uuidstr, domain->name);
return NULL;
}
return vm;
}
static int
vzDoCmdRun(char **outbuf, const char *binary, va_list list)
{
virCommandPtr cmd = virCommandNewVAList(binary, list);
int ret = -1;
if (outbuf)
virCommandSetOutputBuffer(cmd, outbuf);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
ret = 0;
cleanup:
virCommandFree(cmd);
if (ret && outbuf)
VIR_FREE(*outbuf);
return ret;
}
/*
* Run command and return its output, pointer to
* buffer or NULL in case of error. Caller os responsible
* for freeing the buffer.
*/
char *
vzGetOutput(const char *binary, ...)
{
char *outbuf;
va_list list;
int ret;
va_start(list, binary);
ret = vzDoCmdRun(&outbuf, binary, list);
va_end(list);
if (ret)
return NULL;
return outbuf;
}
vz: fix race condition when adding domain to domains list Race condition: User calls defineXML to create new instance. The main thread from vzDomainDefineXMLFlags() creates new instance by prlsdkCreateVm. Then this thread calls prlsdkAddDomain to add new domain to domains list. The second thread receives notification from hypervisor that new VM was created. It calls prlsdkHandleVmAddedEvent() and also tries to add new domain to domains list. These two threads call virDomainObjListFindByUUID() from prlsdkAddDomain() and don't find new domain. So they add two domains with the same uuid to domains list. This fix splits logic of prlsdkAddDomain() into two functions. 1. vzNewDomain() creates new empty domain in domains list with the specific uuid. 2. prlsdkLoadDomain() add data from VM to domain object. New algorithm for creating an instance: In vzDomainDefineXMLFlags() we add new domain to domain list by calling vzNewDomain() and only after that we call CreateVm() to create VM. It means that we "reserve" domain object with the specific uuid. After creation of new VM we add info from this VM to reserved domain object by calling prlsdkLoadDomain(). Before this patch prlsdkLoadDomain() worked in 2 different cases: 1. It creates and initializes new domain. Then updates it from sdk handle. 2. It updates existed domain from sdk handle. In this patch we remove code which creates new domain from LoadDomain() and move it to vzNewDomain(). Now prlsdkLoadDomain() only updates domain from skd handle. In notification handler prlsdkHandleVmAddedEvent() we check the existence of a domain and if it doesn't exist we add new domain by calling vzNewDomain() and load info from sdk handle via prlsdkLoadDomain().
2016-02-10 09:39:14 +00:00
virDomainObjPtr
vzNewDomain(vzDriverPtr driver, const char *name, const unsigned char *uuid)
vz: fix race condition when adding domain to domains list Race condition: User calls defineXML to create new instance. The main thread from vzDomainDefineXMLFlags() creates new instance by prlsdkCreateVm. Then this thread calls prlsdkAddDomain to add new domain to domains list. The second thread receives notification from hypervisor that new VM was created. It calls prlsdkHandleVmAddedEvent() and also tries to add new domain to domains list. These two threads call virDomainObjListFindByUUID() from prlsdkAddDomain() and don't find new domain. So they add two domains with the same uuid to domains list. This fix splits logic of prlsdkAddDomain() into two functions. 1. vzNewDomain() creates new empty domain in domains list with the specific uuid. 2. prlsdkLoadDomain() add data from VM to domain object. New algorithm for creating an instance: In vzDomainDefineXMLFlags() we add new domain to domain list by calling vzNewDomain() and only after that we call CreateVm() to create VM. It means that we "reserve" domain object with the specific uuid. After creation of new VM we add info from this VM to reserved domain object by calling prlsdkLoadDomain(). Before this patch prlsdkLoadDomain() worked in 2 different cases: 1. It creates and initializes new domain. Then updates it from sdk handle. 2. It updates existed domain from sdk handle. In this patch we remove code which creates new domain from LoadDomain() and move it to vzNewDomain(). Now prlsdkLoadDomain() only updates domain from skd handle. In notification handler prlsdkHandleVmAddedEvent() we check the existence of a domain and if it doesn't exist we add new domain by calling vzNewDomain() and load info from sdk handle via prlsdkLoadDomain().
2016-02-10 09:39:14 +00:00
{
virDomainDefPtr def = NULL;
virDomainObjPtr dom = NULL;
vzDomObjPtr pdom = NULL;
if (!(def = virDomainDefNewFull(name, uuid, -1)))
goto error;
if (VIR_ALLOC(pdom) < 0)
goto error;
pdom->stats = PRL_INVALID_HANDLE;
def->virtType = VIR_DOMAIN_VIRT_VZ;
vz: fix race condition when adding domain to domains list Race condition: User calls defineXML to create new instance. The main thread from vzDomainDefineXMLFlags() creates new instance by prlsdkCreateVm. Then this thread calls prlsdkAddDomain to add new domain to domains list. The second thread receives notification from hypervisor that new VM was created. It calls prlsdkHandleVmAddedEvent() and also tries to add new domain to domains list. These two threads call virDomainObjListFindByUUID() from prlsdkAddDomain() and don't find new domain. So they add two domains with the same uuid to domains list. This fix splits logic of prlsdkAddDomain() into two functions. 1. vzNewDomain() creates new empty domain in domains list with the specific uuid. 2. prlsdkLoadDomain() add data from VM to domain object. New algorithm for creating an instance: In vzDomainDefineXMLFlags() we add new domain to domain list by calling vzNewDomain() and only after that we call CreateVm() to create VM. It means that we "reserve" domain object with the specific uuid. After creation of new VM we add info from this VM to reserved domain object by calling prlsdkLoadDomain(). Before this patch prlsdkLoadDomain() worked in 2 different cases: 1. It creates and initializes new domain. Then updates it from sdk handle. 2. It updates existed domain from sdk handle. In this patch we remove code which creates new domain from LoadDomain() and move it to vzNewDomain(). Now prlsdkLoadDomain() only updates domain from skd handle. In notification handler prlsdkHandleVmAddedEvent() we check the existence of a domain and if it doesn't exist we add new domain by calling vzNewDomain() and load info from sdk handle via prlsdkLoadDomain().
2016-02-10 09:39:14 +00:00
if (!(dom = virDomainObjListAdd(driver->domains, def,
driver->xmlopt,
vz: fix race condition when adding domain to domains list Race condition: User calls defineXML to create new instance. The main thread from vzDomainDefineXMLFlags() creates new instance by prlsdkCreateVm. Then this thread calls prlsdkAddDomain to add new domain to domains list. The second thread receives notification from hypervisor that new VM was created. It calls prlsdkHandleVmAddedEvent() and also tries to add new domain to domains list. These two threads call virDomainObjListFindByUUID() from prlsdkAddDomain() and don't find new domain. So they add two domains with the same uuid to domains list. This fix splits logic of prlsdkAddDomain() into two functions. 1. vzNewDomain() creates new empty domain in domains list with the specific uuid. 2. prlsdkLoadDomain() add data from VM to domain object. New algorithm for creating an instance: In vzDomainDefineXMLFlags() we add new domain to domain list by calling vzNewDomain() and only after that we call CreateVm() to create VM. It means that we "reserve" domain object with the specific uuid. After creation of new VM we add info from this VM to reserved domain object by calling prlsdkLoadDomain(). Before this patch prlsdkLoadDomain() worked in 2 different cases: 1. It creates and initializes new domain. Then updates it from sdk handle. 2. It updates existed domain from sdk handle. In this patch we remove code which creates new domain from LoadDomain() and move it to vzNewDomain(). Now prlsdkLoadDomain() only updates domain from skd handle. In notification handler prlsdkHandleVmAddedEvent() we check the existence of a domain and if it doesn't exist we add new domain by calling vzNewDomain() and load info from sdk handle via prlsdkLoadDomain().
2016-02-10 09:39:14 +00:00
0, NULL)))
goto error;
dom->privateData = pdom;
dom->privateDataFreeFunc = prlsdkDomObjFreePrivate;
dom->persistent = 1;
return dom;
error:
virDomainDefFree(def);
VIR_FREE(pdom);
return NULL;
}
static void
vzInitCaps(unsigned long vzVersion, vzCapabilitiesPtr vzCaps)
{
if (vzVersion < VIRTUOZZO_VER_7) {
vzCaps->ctDiskFormat = VIR_STORAGE_FILE_PLOOP;
vzCaps->vmDiskFormat = VIR_STORAGE_FILE_PLOOP;
vzCaps->diskBuses = vz6DiskBuses;
vzCaps->controllerTypes = vz6ControllerTypes;
vzCaps->scsiControllerModel = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
} else {
vzCaps->ctDiskFormat = VIR_STORAGE_FILE_PLOOP;
vzCaps->vmDiskFormat = VIR_STORAGE_FILE_QCOW2;
vzCaps->diskBuses = vz7DiskBuses;
vzCaps->controllerTypes = vz7ControllerTypes;
vzCaps->scsiControllerModel = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI;
}
}
int
vzInitVersion(vzDriverPtr driver)
{
char *output, *sVer, *tmp;
const char *searchStr = "prlsrvctl version ";
int ret = -1;
output = vzGetOutput(PRLSRVCTL, "--help", NULL);
if (!output) {
vzParseError();
goto cleanup;
}
if (!(sVer = strstr(output, searchStr))) {
vzParseError();
goto cleanup;
}
sVer = sVer + strlen(searchStr);
/* parallels server has versions number like 6.0.17977.782218 or 7.0.0,
* In libvirt we handle only first two numbers. */
if (!(tmp = strchr(sVer, '.'))) {
vzParseError();
goto cleanup;
}
if (!(tmp = strchr(tmp + 1, '.'))) {
vzParseError();
goto cleanup;
}
tmp[0] = '\0';
if (virParseVersionString(sVer, &(driver->vzVersion), true) < 0) {
vzParseError();
goto cleanup;
}
vzInitCaps(driver->vzVersion, &driver->vzCaps);
ret = 0;
cleanup:
VIR_FREE(output);
return ret;
}
static int
vzCheckDiskAddressDriveUnsupportedParams(virDomainDiskDefPtr disk)
{
virDomainDeviceDriveAddressPtr drive = &disk->info.addr.drive;
int devIdx, busIdx;
if (drive->controller > 0) {
/* We have only one controller of each type */
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid drive address of disk %s, vz driver "
"supports only one controller."), disk->dst);
return -1;
}
if (drive->target > 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid drive address of disk %s, vz driver "
"supports only target 0."), disk->dst);
return -1;
}
switch (disk->bus) {
case VIR_DOMAIN_DISK_BUS_IDE:
if (drive->unit > 1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid drive address of disk %s, vz driver "
"supports only units 0-1 for IDE bus."),
disk->dst);
return -1;
}
break;
case VIR_DOMAIN_DISK_BUS_SCSI:
case VIR_DOMAIN_DISK_BUS_SATA:
if (drive->bus > 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid drive address of disk %s, vz driver "
"supports only bus 0 for SATA and SCSI bus."),
disk->dst);
return -1;
}
break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Specified disk bus is not supported by vz driver."));
return -1;
}
if (virDiskNameToBusDeviceIndex(disk, &busIdx, &devIdx) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot convert disk '%s' to bus/device index"),
disk->dst);
return -1;
}
if (busIdx != drive->bus || devIdx != drive->unit) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid drive address of disk %s, vz driver "
"does not support non default name mappings."),
disk->dst);
return -1;
}
return 0;
}
static int
vzCheckDiskUnsupportedParams(virDomainDiskDefPtr disk)
{
if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK &&
disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only hard disks and cdroms are supported "
"by vz driver."));
return -1;
}
if (disk->blockio.logical_block_size ||
disk->blockio.physical_block_size) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting disk block sizes is not "
"supported by vz driver."));
return -1;
}
if (disk->blkdeviotune.total_bytes_sec ||
disk->blkdeviotune.read_bytes_sec ||
disk->blkdeviotune.write_bytes_sec ||
disk->blkdeviotune.total_iops_sec ||
disk->blkdeviotune.read_iops_sec ||
disk->blkdeviotune.write_iops_sec) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting disk io limits is not "
"supported by vz driver yet."));
return -1;
}
if (disk->serial) {
VIR_INFO("%s", _("Setting disk serial number is not "
"supported by vz driver."));
}
if (disk->wwn) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting disk wwn id is not "
"supported by vz driver."));
return -1;
}
if (disk->vendor) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting disk vendor is not "
"supported by vz driver."));
return -1;
}
if (disk->product) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting disk product id is not "
"supported by vz driver."));
return -1;
}
if (disk->error_policy != VIR_DOMAIN_DISK_ERROR_POLICY_DEFAULT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting disk error policy is not "
"supported by vz driver."));
return -1;
}
if (disk->iomode != VIR_DOMAIN_DISK_IO_DEFAULT &&
disk->iomode != VIR_DOMAIN_DISK_IO_NATIVE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only native iomode is "
"supported by vz driver."));
return -1;
}
if (disk->copy_on_read) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Disk copy_on_read is not "
"supported by vz driver."));
return -1;
}
if (disk->startupPolicy != VIR_DOMAIN_STARTUP_POLICY_DEFAULT) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting up disk startup policy is not "
"supported by vz driver."));
return -1;
}
if (disk->transient) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Transient disks are not "
"supported by vz driver."));
return -1;
}
if (disk->discard) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting up disk discard parameter is not "
"supported by vz driver."));
return -1;
}
if (disk->iothread) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Setting up disk io thread # is not "
"supported by vz driver."));
return -1;
}
if (disk->src->type != VIR_STORAGE_TYPE_FILE &&
disk->src->type != VIR_STORAGE_TYPE_BLOCK) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Only disk and block storage types are "
"supported by vz driver."));
return -1;
}
if (vzCheckDiskAddressDriveUnsupportedParams(disk) < 0)
return -1;
return 0;
}
int
vzCheckUnsupportedDisk(const virDomainDef *def,
virDomainDiskDefPtr disk,
vzCapabilitiesPtr vzCaps)
{
size_t i;
virStorageFileFormat diskFormat;
if (vzCheckDiskUnsupportedParams(disk) < 0)
return -1;
if (disk->src->type == VIR_STORAGE_TYPE_FILE) {
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
if (IS_CT(def))
diskFormat = vzCaps->ctDiskFormat;
else
diskFormat = vzCaps->vmDiskFormat;
} else {
diskFormat = VIR_STORAGE_FILE_RAW;
}
} else {
diskFormat = VIR_STORAGE_FILE_RAW;
}
if (virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_NONE &&
virDomainDiskGetFormat(disk) != diskFormat) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported format of disk %s"),
disk->src->path);
return -1;
}
for (i = 0; vzCaps->diskBuses[i] != VIR_DOMAIN_DISK_BUS_LAST; i++) {
if (disk->bus == vzCaps->diskBuses[i])
break;
}
if (vzCaps->diskBuses[i] == VIR_DOMAIN_DISK_BUS_LAST) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported disk bus type %s"),
virDomainDiskBusTypeToString(disk->bus));
return -1;
}
return 0;
}
int
vzCheckUnsupportedControllers(virDomainDefPtr def, vzCapabilitiesPtr vzCaps)
{
size_t i, j;
virDomainControllerDefPtr controller;
for (i = 0; i < def->ncontrollers; i++) {
controller = def->controllers[i];
for (j = 0; vzCaps->controllerTypes[j] != VIR_DOMAIN_CONTROLLER_TYPE_LAST; j++) {
if (controller->type == vzCaps->controllerTypes[j])
break;
}
if (vzCaps->controllerTypes[j] == VIR_DOMAIN_CONTROLLER_TYPE_LAST) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported controller type %s"),
virDomainControllerTypeToString(controller->type));
return -1;
}
if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
controller->model != -1 &&
controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO &&
controller->model != vzCaps->scsiControllerModel) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported SCSI controller model %s"),
virDomainControllerModelSCSITypeToString(controller->model));
return -1;
}
}
return 0;
}
int vzGetDefaultSCSIModel(vzDriverPtr driver,
PRL_CLUSTERED_DEVICE_SUBTYPE *scsiModel)
{
switch (driver->vzCaps.scsiControllerModel) {
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
*scsiModel = PCD_VIRTIO_SCSI;
break;
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
*scsiModel = PCD_BUSLOGIC;
break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown SCSI controller model %s"),
virDomainControllerModelSCSITypeToString(
driver->vzCaps.scsiControllerModel));
return -1;
}
return 0;
}
int vzCheckUnsupportedGraphics(virDomainGraphicsDefPtr gr)
{
if (gr->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vz driver supports only "
"VNC graphics."));
return -1;
}
if (gr->data.vnc.websocket != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vz driver doesn't support "
"websockets for VNC graphics."));
return -1;
}
if (gr->data.vnc.keymap != 0 &&
STRNEQ(gr->data.vnc.keymap, "en-us")) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vz driver supports only "
"\"en-us\" keymap for VNC graphics."));
return -1;
}
if (gr->data.vnc.sharePolicy == VIR_DOMAIN_GRAPHICS_VNC_SHARE_ALLOW_EXCLUSIVE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vz driver doesn't support "
"exclusive share policy for VNC graphics."));
return -1;
}
if (gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_FAIL ||
gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vz driver doesn't support "
"given action in case of password change."));
return -1;
}
if (gr->data.vnc.auth.expires) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vz driver doesn't support "
"setting password expire time."));
return -1;
}
if (gr->nListens > 1) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("vz driver doesn't support more than "
"one listening VNC server per domain"));
return -1;
}
if (gr->nListens == 1 &&
gr->listens[0].type != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("vz driver supports only address-based VNC listening"));
return -1;
}
return 0;
}