vz_utils.c 20.0 KB
Newer Older
1
/*
2
 * vz_utils.c: core driver functions for managing
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * 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>

27
#include "vircommand.h"
28
#include "virerror.h"
29
#include "viralloc.h"
30
#include "virjson.h"
31
#include "vz_utils.h"
32
#include "vz_sdk.h"
33
#include "virstring.h"
34
#include "datatypes.h"
35
#include "virlog.h"
36
#include "virtime.h"
37 38

#define VIR_FROM_THIS VIR_FROM_PARALLELS
39
#define PRLSRVCTL "prlsrvctl"
40

41 42
VIR_LOG_INIT("parallels.utils");

43 44 45 46 47 48 49 50 51
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};

52 53 54 55 56 57 58 59 60
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};

61
/**
62
 * vzDomObjFromDomain:
63 64 65 66 67 68 69 70 71
 * @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
72
vzDomObjFromDomain(virDomainPtr domain)
73 74
{
    virDomainObjPtr vm;
75
    vzConnPtr privconn = domain->conn->privateData;
76
    char uuidstr[VIR_UUID_STRING_BUFLEN];
77
    vzDriverPtr driver = privconn->driver;
78

79
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
80 81 82 83 84 85 86 87 88 89 90
    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;
}

91
/**
92
 * vzDomObjFromDomainRef:
93 94 95 96 97 98 99 100 101
 * @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
102
vzDomObjFromDomainRef(virDomainPtr domain)
103 104
{
    virDomainObjPtr vm;
105
    vzConnPtr privconn = domain->conn->privateData;
106
    char uuidstr[VIR_UUID_STRING_BUFLEN];
107
    vzDriverPtr driver = privconn->driver;
108

109
    vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
110 111 112 113 114 115 116 117 118 119
    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;
}
120

121
static int
122
vzDoCmdRun(char **outbuf, const char *binary, va_list list)
123 124 125 126 127 128 129
{
    virCommandPtr cmd = virCommandNewVAList(binary, list);
    int ret = -1;

    if (outbuf)
        virCommandSetOutputBuffer(cmd, outbuf);

130
    if (virCommandRun(cmd, NULL) < 0)
131 132 133 134
        goto cleanup;

    ret = 0;

135
 cleanup:
136
    virCommandFree(cmd);
137
    if (ret && outbuf)
138 139 140 141 142 143 144 145 146 147
        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 *
148
vzGetOutput(const char *binary, ...)
149 150 151 152 153 154
{
    char *outbuf;
    va_list list;
    int ret;

    va_start(list, binary);
155
    ret = vzDoCmdRun(&outbuf, binary, list);
156 157 158 159 160 161
    va_end(list);
    if (ret)
        return NULL;

    return outbuf;
}
162

163
static void
164
vzInitCaps(unsigned long vzVersion, vzCapabilitiesPtr vzCaps)
165 166 167 168 169
{
    if (vzVersion < VIRTUOZZO_VER_7) {
        vzCaps->ctDiskFormat = VIR_STORAGE_FILE_PLOOP;
        vzCaps->vmDiskFormat = VIR_STORAGE_FILE_PLOOP;
        vzCaps->diskBuses = vz6DiskBuses;
170 171
        vzCaps->controllerTypes = vz6ControllerTypes;
        vzCaps->scsiControllerModel = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
172 173 174 175
    } else {
        vzCaps->ctDiskFormat = VIR_STORAGE_FILE_PLOOP;
        vzCaps->vmDiskFormat = VIR_STORAGE_FILE_QCOW2;
        vzCaps->diskBuses = vz7DiskBuses;
176 177
        vzCaps->controllerTypes = vz7ControllerTypes;
        vzCaps->scsiControllerModel = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI;
178 179 180
    }
}

181
int
182
vzInitVersion(vzDriverPtr driver)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
{
    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';
215
    if (virParseVersionString(sVer, &(driver->vzVersion), true) < 0) {
216 217 218 219
        vzParseError();
        goto cleanup;
    }

220
    vzInitCaps(driver->vzVersion, &driver->vzCaps);
221 222 223 224 225 226
    ret = 0;

 cleanup:
    VIR_FREE(output);
    return ret;
}
227

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
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;
}

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
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;
    }

326 327 328
    if (disk->serial && disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
        VIR_INFO("%s", _("Setting disk serial number is "
                         "supported only for disk devices."));
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    }

    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;
    }

M
Mikhail Feoktistov 已提交
359 360
    if (disk->iomode != VIR_DOMAIN_DISK_IO_DEFAULT &&
        disk->iomode != VIR_DOMAIN_DISK_IO_NATIVE) {
361
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
M
Mikhail Feoktistov 已提交
362
                       _("Only native iomode is "
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
                         "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;

    }

412 413 414
    if (vzCheckDiskAddressDriveUnsupportedParams(disk) < 0)
        return -1;

415 416 417
    return 0;
}

418
int
419 420 421
vzCheckUnsupportedDisk(const virDomainDef *def,
                       virDomainDiskDefPtr disk,
                       vzCapabilitiesPtr vzCaps)
422
{
423
    size_t i;
424 425
    virStorageFileFormat diskFormat;

426 427
    if (vzCheckDiskUnsupportedParams(disk) < 0)
        return -1;
428

429 430 431 432 433 434
    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;
435
        } else {
436
            diskFormat = VIR_STORAGE_FILE_RAW;
437
        }
438 439 440
    } else {
        diskFormat = VIR_STORAGE_FILE_RAW;
    }
441

442 443 444 445 446 447 448
    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;
    }
449

450 451 452 453
    for (i = 0; vzCaps->diskBuses[i] != VIR_DOMAIN_DISK_BUS_LAST; i++) {
        if (disk->bus == vzCaps->diskBuses[i])
            break;
    }
454

455 456 457 458 459
    if (vzCaps->diskBuses[i] == VIR_DOMAIN_DISK_BUS_LAST) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported disk bus type %s"),
                       virDomainDiskBusTypeToString(disk->bus));
        return -1;
460
    }
461

462 463
    return 0;
}
464 465

int
466
vzCheckUnsupportedControllers(const virDomainDef *def, vzCapabilitiesPtr vzCaps)
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
{
    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;
}
M
Mikhail Feoktistov 已提交
499

500
int vzGetDefaultSCSIModel(vzDriverPtr driver,
M
Mikhail Feoktistov 已提交
501 502
                          PRL_CLUSTERED_DEVICE_SUBTYPE *scsiModel)
{
503
    switch ((int)driver->vzCaps.scsiControllerModel) {
M
Mikhail Feoktistov 已提交
504 505 506 507 508 509 510 511 512 513
    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(
514
                           driver->vzCaps.scsiControllerModel));
M
Mikhail Feoktistov 已提交
515 516 517 518
        return -1;
    }
    return 0;
}
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

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;
}
582 583

void*
584
vzDomObjAlloc(void *opaque ATTRIBUTE_UNUSED)
585 586 587 588 589 590
{
    vzDomObjPtr pdom = NULL;

    if (VIR_ALLOC(pdom) < 0)
        return NULL;

591
    if (virCondInit(&pdom->job.cond) < 0)
592 593
        goto error;

594 595 596
    pdom->stats = PRL_INVALID_HANDLE;

    return pdom;
597 598 599 600 601

 error:
    VIR_FREE(pdom);

    return NULL;
602 603 604 605 606 607 608 609 610 611 612 613
}

void
vzDomObjFree(void* p)
{
    vzDomObjPtr pdom = p;

    if (!pdom)
        return;

    PrlHandle_Free(pdom->sdkdom);
    PrlHandle_Free(pdom->stats);
614
    virCondDestroy(&pdom->job.cond);
615 616
    VIR_FREE(pdom);
};
617 618 619 620 621 622 623 624 625 626 627 628 629 630

#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;

631 632
    while (pdom->job.active) {
        if (virCondWaitUntil(&pdom->job.cond, &dom->parent.lock, then) < 0)
633 634 635
            goto error;
    }

636 637 638 639 640 641 642 643
    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;
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
    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;

661
    pdom->job.active = false;
662
    pdom->job.cancelled = false;
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
    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;
685
}