2012-07-31 18:56:07 +00:00
|
|
|
/*
|
2015-06-10 07:50:00 +00:00
|
|
|
* vz_utils.c: core driver functions for managing
|
2012-07-31 18:56:07 +00:00
|
|
|
* 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>
|
|
|
|
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#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"
|
2015-06-10 07:50:00 +00:00
|
|
|
#include "vz_utils.h"
|
2016-02-10 09:39:14 +00:00
|
|
|
#include "vz_sdk.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2015-04-22 16:10:50 +00:00
|
|
|
#include "datatypes.h"
|
2016-03-16 11:55:27 +00:00
|
|
|
#include "virlog.h"
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
#include "virtime.h"
|
2012-07-31 18:56:07 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_PARALLELS
|
2016-03-15 07:47:46 +00:00
|
|
|
#define PRLSRVCTL "prlsrvctl"
|
2012-07-31 18:56:07 +00:00
|
|
|
|
2016-03-16 11:55:27 +00:00
|
|
|
VIR_LOG_INIT("parallels.utils");
|
|
|
|
|
2016-03-15 07:47:47 +00:00
|
|
|
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};
|
|
|
|
|
2016-03-15 07:47:50 +00:00
|
|
|
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};
|
|
|
|
|
2015-04-22 16:10:50 +00:00
|
|
|
/**
|
2015-06-10 07:50:00 +00:00
|
|
|
* vzDomObjFromDomain:
|
2015-04-22 16:10:50 +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 unlocked by virObjectUnlock().
|
|
|
|
*
|
|
|
|
* Returns the domain object without incremented reference counter which is locked
|
|
|
|
* on success, NULL otherwise.
|
|
|
|
*/
|
|
|
|
virDomainObjPtr
|
2015-06-10 07:50:00 +00:00
|
|
|
vzDomObjFromDomain(virDomainPtr domain)
|
2015-04-22 16:10:50 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
2015-06-10 07:50:00 +00:00
|
|
|
vzConnPtr privconn = domain->conn->privateData;
|
2015-04-22 16:10:50 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2016-03-28 19:11:30 +00:00
|
|
|
vzDriverPtr driver = privconn->driver;
|
2015-04-22 16:10:50 +00:00
|
|
|
|
2016-03-28 19:11:30 +00:00
|
|
|
vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
|
2015-04-22 16:10:50 +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;
|
|
|
|
}
|
|
|
|
|
2015-06-09 07:35:53 +00:00
|
|
|
/**
|
2015-06-10 07:50:00 +00:00
|
|
|
* vzDomObjFromDomainRef:
|
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
|
2015-06-10 07:50:00 +00:00
|
|
|
vzDomObjFromDomainRef(virDomainPtr domain)
|
2015-06-09 07:35:53 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr vm;
|
2015-06-10 07:50:00 +00:00
|
|
|
vzConnPtr privconn = domain->conn->privateData;
|
2015-06-09 07:35:53 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2016-03-28 19:11:30 +00:00
|
|
|
vzDriverPtr driver = privconn->driver;
|
2015-06-09 07:35:53 +00:00
|
|
|
|
2016-03-28 19:11:30 +00:00
|
|
|
vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
|
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;
|
|
|
|
}
|
2015-04-22 16:10:50 +00:00
|
|
|
|
2012-07-31 18:56:07 +00:00
|
|
|
static int
|
2015-06-10 07:50:00 +00:00
|
|
|
vzDoCmdRun(char **outbuf, const char *binary, va_list list)
|
2012-07-31 18:56:07 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = virCommandNewVAList(binary, list);
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (outbuf)
|
|
|
|
virCommandSetOutputBuffer(cmd, outbuf);
|
|
|
|
|
2013-01-23 22:04:48 +00:00
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
2012-07-31 18:56:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:57:01 +00:00
|
|
|
cleanup:
|
2012-07-31 18:56:07 +00:00
|
|
|
virCommandFree(cmd);
|
2012-09-10 15:23:43 +00:00
|
|
|
if (ret && outbuf)
|
2012-07-31 18:56:07 +00:00
|
|
|
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 *
|
2015-06-10 07:50:00 +00:00
|
|
|
vzGetOutput(const char *binary, ...)
|
2012-07-31 18:56:07 +00:00
|
|
|
{
|
|
|
|
char *outbuf;
|
|
|
|
va_list list;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
va_start(list, binary);
|
2015-06-10 07:50:00 +00:00
|
|
|
ret = vzDoCmdRun(&outbuf, binary, list);
|
2012-07-31 18:56:07 +00:00
|
|
|
va_end(list);
|
|
|
|
if (ret)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return outbuf;
|
|
|
|
}
|
2016-02-10 09:39:14 +00:00
|
|
|
|
2016-03-15 07:47:47 +00:00
|
|
|
static void
|
2016-03-28 19:11:30 +00:00
|
|
|
vzInitCaps(unsigned long vzVersion, vzCapabilitiesPtr vzCaps)
|
2016-03-15 07:47:47 +00:00
|
|
|
{
|
|
|
|
if (vzVersion < VIRTUOZZO_VER_7) {
|
|
|
|
vzCaps->ctDiskFormat = VIR_STORAGE_FILE_PLOOP;
|
|
|
|
vzCaps->vmDiskFormat = VIR_STORAGE_FILE_PLOOP;
|
|
|
|
vzCaps->diskBuses = vz6DiskBuses;
|
2016-03-15 07:47:50 +00:00
|
|
|
vzCaps->controllerTypes = vz6ControllerTypes;
|
|
|
|
vzCaps->scsiControllerModel = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
|
2016-03-15 07:47:47 +00:00
|
|
|
} else {
|
|
|
|
vzCaps->ctDiskFormat = VIR_STORAGE_FILE_PLOOP;
|
|
|
|
vzCaps->vmDiskFormat = VIR_STORAGE_FILE_QCOW2;
|
|
|
|
vzCaps->diskBuses = vz7DiskBuses;
|
2016-03-15 07:47:50 +00:00
|
|
|
vzCaps->controllerTypes = vz7ControllerTypes;
|
|
|
|
vzCaps->scsiControllerModel = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI;
|
2016-03-15 07:47:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 07:47:46 +00:00
|
|
|
int
|
2016-03-28 19:11:30 +00:00
|
|
|
vzInitVersion(vzDriverPtr driver)
|
2016-03-15 07:47:46 +00:00
|
|
|
{
|
|
|
|
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';
|
2016-03-28 19:11:30 +00:00
|
|
|
if (virParseVersionString(sVer, &(driver->vzVersion), true) < 0) {
|
2016-03-15 07:47:46 +00:00
|
|
|
vzParseError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-03-28 19:11:30 +00:00
|
|
|
vzInitCaps(driver->vzVersion, &driver->vzCaps);
|
2016-03-15 07:47:46 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(output);
|
|
|
|
return ret;
|
|
|
|
}
|
2016-03-15 07:47:48 +00:00
|
|
|
|
2016-04-20 14:05:33 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-03-16 11:55:27 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-09-22 14:55:41 +00:00
|
|
|
if (disk->serial && disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
VIR_INFO("%s", _("Setting disk serial number is "
|
|
|
|
"supported only for disk devices."));
|
2016-03-16 11:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-04-12 13:57:56 +00:00
|
|
|
if (disk->iomode != VIR_DOMAIN_DISK_IO_DEFAULT &&
|
|
|
|
disk->iomode != VIR_DOMAIN_DISK_IO_NATIVE) {
|
2016-03-16 11:55:27 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2016-04-12 13:57:56 +00:00
|
|
|
_("Only native iomode is "
|
2016-03-16 11:55:27 +00:00
|
|
|
"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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-04-20 14:05:33 +00:00
|
|
|
if (vzCheckDiskAddressDriveUnsupportedParams(disk) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-03-16 11:55:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-15 07:47:48 +00:00
|
|
|
int
|
2016-04-20 14:05:32 +00:00
|
|
|
vzCheckUnsupportedDisk(const virDomainDef *def,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
vzCapabilitiesPtr vzCaps)
|
2016-03-15 07:47:48 +00:00
|
|
|
{
|
2016-04-20 14:05:32 +00:00
|
|
|
size_t i;
|
2016-03-15 07:47:48 +00:00
|
|
|
virStorageFileFormat diskFormat;
|
|
|
|
|
2016-04-20 14:05:32 +00:00
|
|
|
if (vzCheckDiskUnsupportedParams(disk) < 0)
|
|
|
|
return -1;
|
2016-03-16 11:55:27 +00:00
|
|
|
|
2016-04-20 14:05:32 +00:00
|
|
|
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;
|
2016-03-15 07:47:48 +00:00
|
|
|
} else {
|
2016-04-08 07:41:32 +00:00
|
|
|
diskFormat = VIR_STORAGE_FILE_RAW;
|
2016-03-15 07:47:48 +00:00
|
|
|
}
|
2016-04-20 14:05:32 +00:00
|
|
|
} else {
|
|
|
|
diskFormat = VIR_STORAGE_FILE_RAW;
|
|
|
|
}
|
2016-03-15 07:47:48 +00:00
|
|
|
|
2016-04-20 14:05:32 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-04-08 07:41:32 +00:00
|
|
|
|
2016-04-20 14:05:32 +00:00
|
|
|
for (i = 0; vzCaps->diskBuses[i] != VIR_DOMAIN_DISK_BUS_LAST; i++) {
|
|
|
|
if (disk->bus == vzCaps->diskBuses[i])
|
|
|
|
break;
|
|
|
|
}
|
2016-03-15 07:47:48 +00:00
|
|
|
|
2016-04-20 14:05:32 +00:00
|
|
|
if (vzCaps->diskBuses[i] == VIR_DOMAIN_DISK_BUS_LAST) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported disk bus type %s"),
|
|
|
|
virDomainDiskBusTypeToString(disk->bus));
|
|
|
|
return -1;
|
2016-03-15 07:47:48 +00:00
|
|
|
}
|
2016-04-20 14:05:32 +00:00
|
|
|
|
2016-03-15 07:47:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-03-15 07:47:50 +00:00
|
|
|
|
|
|
|
int
|
2016-08-18 11:43:09 +00:00
|
|
|
vzCheckUnsupportedControllers(const virDomainDef *def, vzCapabilitiesPtr vzCaps)
|
2016-03-15 07:47:50 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2016-03-15 07:47:51 +00:00
|
|
|
|
2016-03-28 19:11:30 +00:00
|
|
|
int vzGetDefaultSCSIModel(vzDriverPtr driver,
|
2016-03-15 07:47:51 +00:00
|
|
|
PRL_CLUSTERED_DEVICE_SUBTYPE *scsiModel)
|
|
|
|
{
|
2016-03-28 19:11:30 +00:00
|
|
|
switch (driver->vzCaps.scsiControllerModel) {
|
2016-03-15 07:47:51 +00:00
|
|
|
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(
|
2016-03-28 19:11:30 +00:00
|
|
|
driver->vzCaps.scsiControllerModel));
|
2016-03-15 07:47:51 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2016-04-20 14:05:42 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2016-06-14 08:45:56 +00:00
|
|
|
|
|
|
|
void*
|
|
|
|
vzDomObjAlloc(void)
|
|
|
|
{
|
|
|
|
vzDomObjPtr pdom = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(pdom) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2016-06-20 10:08:14 +00:00
|
|
|
if (virCondInit(&pdom->job.cond) < 0)
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
goto error;
|
|
|
|
|
2016-06-14 08:45:56 +00:00
|
|
|
pdom->stats = PRL_INVALID_HANDLE;
|
|
|
|
|
|
|
|
return pdom;
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(pdom);
|
|
|
|
|
|
|
|
return NULL;
|
2016-06-14 08:45:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vzDomObjFree(void* p)
|
|
|
|
{
|
|
|
|
vzDomObjPtr pdom = p;
|
|
|
|
|
|
|
|
if (!pdom)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PrlHandle_Free(pdom->sdkdom);
|
|
|
|
PrlHandle_Free(pdom->stats);
|
2016-06-20 10:08:14 +00:00
|
|
|
virCondDestroy(&pdom->job.cond);
|
2016-06-14 08:45:56 +00:00
|
|
|
VIR_FREE(pdom);
|
|
|
|
};
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
|
|
|
|
#define VZ_JOB_WAIT_TIME (1000 * 30)
|
|
|
|
|
|
|
|
int
|
|
|
|
vzDomainObjBeginJob(virDomainObjPtr dom)
|
|
|
|
{
|
|
|
|
vzDomObjPtr pdom = dom->privateData;
|
|
|
|
unsigned long long now;
|
|
|
|
unsigned long long then;
|
|
|
|
|
|
|
|
if (virTimeMillisNow(&now) < 0)
|
|
|
|
return -1;
|
|
|
|
then = now + VZ_JOB_WAIT_TIME;
|
|
|
|
|
2016-06-20 10:08:14 +00:00
|
|
|
while (pdom->job.active) {
|
|
|
|
if (virCondWaitUntil(&pdom->job.cond, &dom->parent.lock, then) < 0)
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2016-06-20 10:08:14 +00:00
|
|
|
if (virTimeMillisNow(&now) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
pdom->job.active = true;
|
|
|
|
pdom->job.started = now;
|
|
|
|
pdom->job.elapsed = 0;
|
|
|
|
pdom->job.progress = 0;
|
|
|
|
pdom->job.hasProgress = false;
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (errno == ETIMEDOUT)
|
|
|
|
virReportError(VIR_ERR_OPERATION_TIMEOUT,
|
|
|
|
"%s", _("cannot acquire state change lock"));
|
|
|
|
else
|
|
|
|
virReportSystemError(errno,
|
|
|
|
"%s", _("cannot acquire job mutex"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vzDomainObjEndJob(virDomainObjPtr dom)
|
|
|
|
{
|
|
|
|
vzDomObjPtr pdom = dom->privateData;
|
|
|
|
|
2016-06-20 10:08:14 +00:00
|
|
|
pdom->job.active = false;
|
2017-01-31 07:44:12 +00:00
|
|
|
pdom->job.cancelled = false;
|
2016-06-20 10:08:14 +00:00
|
|
|
virCondSignal(&pdom->job.cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vzDomainJobUpdateTime(vzDomainJobObjPtr job)
|
|
|
|
{
|
|
|
|
unsigned long long now;
|
|
|
|
|
|
|
|
if (!job->started)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virTimeMillisNow(&now) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (now < job->started) {
|
|
|
|
VIR_WARN("Async job starts in the future");
|
|
|
|
job->started = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
job->elapsed = now - job->started;
|
|
|
|
return 0;
|
vz: make vz driver more responsive
Current vz driver implementation is not usable when it comes to
long runnig operations. Migration or saving a domain blocks all
other operations even query ones which are expecteted to be available.
This patch addresses this problem.
All vz driver API calls fall into next 3 groups:
1. only query domain cache (virDomainObj, vz cache statistic)
examples are vzDomainGetState, vzDomainGetXMLDesc etc.
2. use thread shared sdkdom object
examples are vzDomainSetMemoryFlags, vzDomainAttachDevice etc.
3. use no thread shared sdkdom object nor domain cache
examples are vzDomainSnapshotListNames, vzDomainSnapshotGetXMLDesc etc
API calls from group 1 don't need to be changed as they hold domain lock only
for short period of time. These calls [1] are easily distinguished. They query
domain object thru libvirt common code or query vz sdk statistics handle thru
vz sdk sync operations.
vzDomainInterfaceStats is the only exception. It uses sdkdom object to
convert interface name to its vz sdk stack index which could not be saved in
domain cache. Interface statistics is available thru this stack index as a key
rather than name. As a result we can have accidental 'not known interface'
errors on quering intrerface stats. The reason is that in the process of
updating domain configuration we drop all devices and then recreate them again
in sdkdom object and domain lock can be dropped meanwhile (to remove networks
for existing bridged interfaces and(or) (re)create new ones). We can fix this
by changing the way we support bridged interfaces or by reordering operations
and changing bridged networks beforehand. Anyway this is better than moving
this API call into 2 group and making it an exclusive job.
As to API calls from group 2, first thread shared sdkdom object needs to be
explained. vz sdk has only one handle for a given domain, thus threads need
exclusive access to operate on it. These calls are fixed to drop and reacquire
domain lock on any lengthy operations - namely waiting the result of async vz
sdk operation. As lock is dropped we need to take extra reference to domain
object if it is not taken already as domain object can be deleted from list
while lock is dropped. As this operations use thread shared sdkdom object, the
simplest way to make calls from group 2 be consistent to each other is to make
them mutually exclusive. This is done by taking/releasing job condition thru
calling correspondent job routine. This approach makes group 1 and group
2 calls consistent to each other too. Not all calls of group 2 change the
domain cache but those that do update it thru prlsdkUpdateDomain which holds
the lock thoughout the update.
API calls from group [2] are easily distinguished too. They use
beginEdit/commit to change domain configuration (vzDomainSetMemoryFlags) or/and
update domain cache from sdkdom at the end of operation (vzDomainSuspend).
There is a known issue however. Frankly speaking it was introduced by ealier
patch '[PATCH 6/9] vz: cleanup loading domain code' from a different series.
The patch significantly reduced amount of time when the driver lock is held when
creating domain from API call or as a result of domain added event from vz sdk.
The problem is these two paths race on using thread shared sdkdom as we don't
have libvirt domain object and can not lock on it. However this don't
invalidates the patch as we can't use the former approach of preadding domain
into the list as we need name at least and name is not given by event. Anyway
i'm against adding half baked object into the list. Eventually this race can be
fixed by extra measures. As to current situation races with different
configurations are unlikely and race when adding domain thru vz driver and
simultaneous event from vz sdk is not dangerous as configuration is the same.
The last group [3] is API calls that need only sdkdom object to make vz sdk
call and don't change thread shared sdkdom object or domain cache in any way.
For now these are mostly domain snapshot API calls. The changes are similar to
those of group 2 - they add extra reference and drop/reacquire the lock on waiting
vz async call result. One can simply take the immutable sdkdom object from the
cache and drop the lock for the rest of operations but the chosen approach
makes implementation of these API calls somewhat similar to those of from group
2 and thus a bit futureproof. As calls of group 3 don't need vz driver
domain/vz sdk cache in any way, they are consistent with respect to API calls from
groups 1 and 3.
There is another exception. Calls to make-snapshot/revert-to-snapshot/migrate
are moved to group 2. That is they are made mutually exclusive. The reason
is that libvirt API supports control/query only for one job per domain and
these are jobs that are likely to be queried/aborted.
Appendix.
[1] API calls that only query domain cache.
(marked [*] are included for a different reason)
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
.domainGetState = vzDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */ [*]
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
[2] API calls that use thread shared sdkdom object
(marked [*] are included for a different reason)
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
.domainResume = vzDomainResume, /* 0.10.0 */
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
.domainCreate = vzDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
.domainReboot = vzDomainReboot, /* 1.3.0 */
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ (update part)
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
.domainSetUserPassword = vzDomainSetUserPassword, /* 1.3.6 */
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */ [*]
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */ [*]
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ [*]
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
prlsdkHandleVmConfigEvent
[3] API calls that do not use thread shared sdkdom object
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
[4] Known issues.
1. accidental errors on getting network statistics
2. race with simultaneous use of thread shared domain object on paths
of adding domain thru API and adding domain on vz sdk domain added event.
2016-07-20 15:00:33 +00:00
|
|
|
}
|