Commit message: libxl: Modify name of shutdown thread

The current thread name 'ev-<domid>' is a bit terse. Change the name
to 'shutdown-event-<domid>', allowing it to be distinguished between
thread handling other event types.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
CVE: CVE-2021-4147
CWE: CWE-667
Vulnerability description: A flaw was found in the libvirt libxl driver. A malicious guest could continuously reboot itself and cause libvirtd on the host to deadlock or crash, resulting in a denial of service condition.

Project: libvirt
File: libxl_domain.c

libxlDomainStart(libxlDriverPrivate *driver,
                 virDomainObj *vm,
                 bool start_paused,
                 int restore_fd,
                 uint32_t restore_ver)
{
    virObjectEvent *event = NULL;

    if (libxlDomainStartPrepare(driver, vm) < 0)
        return -1;

    if (libxlDomainStartPerform(driver, vm, start_paused,
                                restore_fd, restore_ver) < 0) {
        libxlDomainCleanup(driver, vm);
        return -1;
    }

    if (g_atomic_int_add(&driver->nactive, 1) == 0 && driver->inhibitCallback)
        driver->inhibitCallback(true, driver->inhibitOpaque);

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED,
                                              restore_fd < 0 ?
                                              VIR_DOMAIN_EVENT_STARTED_BOOTED :
                                              VIR_DOMAIN_EVENT_STARTED_RESTORED);
    virObjectEventStateQueue(driver->domainEventState, event);

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainManagedSavePath(libxlDriverPrivate *driver, virDomainObj *vm)
{
    char *ret;
    g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);

    ret = g_strdup_printf("%s/%s.save", cfg->saveDir, vm->def->name);
    return ret;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED)
{
    libxlDomainObjPrivate *priv;

    priv = g_new0(libxlDomainObjPrivate, 1);

    if (!(priv->devs = virChrdevAlloc())) {
        g_free(priv);
        return NULL;
    }

    if (libxlDomainObjInitJob(priv) < 0) {
        virChrdevFree(priv->devs);
        g_free(priv);
        return NULL;
    }

    return priv;
}

Project: libvirt
File: libxl_domain.c

libxlConsoleCallback(libxl_ctx *ctx, libxl_event *ev, void *for_callback)
{
    virDomainObj *vm = for_callback;
    size_t i;
    virDomainChrDef *chr;
    char *console = NULL;
    int ret;

    virObjectLock(vm);
    for (i = 0; i < vm->def->nconsoles; i++) {
        chr = vm->def->consoles[i];

        if (i == 0 &&
            chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
            chr = vm->def->serials[0];

        if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
            libxl_console_type console_type;

            console_type =
                (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL ?
                 LIBXL_CONSOLE_TYPE_SERIAL : LIBXL_CONSOLE_TYPE_PV);
            ret = libxl_console_get_tty(ctx, ev->domid,
                                        chr->target.port, console_type,
                                        &console);
            if (!ret) {
                VIR_FREE(chr->source->data.file.path);
                if (console && console[0] != '\0')
                    chr->source->data.file.path = g_strdup(console);
            }
            VIR_FREE(console);
        }
    }
    for (i = 0; i < vm->def->nserials; i++) {
        chr = vm->def->serials[i];

        chr->info.alias = g_strdup_printf("serial%zd", i);
        if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
            if (chr->source->data.file.path)
                continue;
            ret = libxl_console_get_tty(ctx, ev->domid,
                                        chr->target.port,
                                        LIBXL_CONSOLE_TYPE_SERIAL,
                                        &console);
            if (!ret) {
                VIR_FREE(chr->source->data.file.path);
                if (console && console[0] != '\0')
                    chr->source->data.file.path = g_strdup(console);
            }
            VIR_FREE(console);
        }
    }
    virObjectUnlock(vm);
    libxl_event_free(ctx, ev);
}

Project: libvirt
File: libxl_domain.c

libxlDomainDefPostParse(virDomainDef *def,
                        unsigned int parseFlags G_GNUC_UNUSED,
                        void *opaque G_GNUC_UNUSED,
                        void *parseOpaque G_GNUC_UNUSED)
{
    /* Xen PV domains always have a PV console, so add one to the domain config
     * via post-parse callback if not explicitly specified in the XML. */
    if (def->os.type != VIR_DOMAIN_OSTYPE_HVM && def->nconsoles == 0) {
        virDomainChrDef *chrdef;

        if (!(chrdef = virDomainChrDefNew(NULL)))
            return -1;

        chrdef->source->type = VIR_DOMAIN_CHR_TYPE_PTY;
        chrdef->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
        chrdef->target.port = 0;
        chrdef->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;

        def->consoles = g_new0(virDomainChrDef *, 1);
        def->nconsoles = 1;
        def->consoles[0] = chrdef;
    }

    /* add implicit input devices */
    if (xenDomainDefAddImplicitInputDevice(def) < 0)
        return -1;

    /* For x86_64 HVM */
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
        def->os.arch == VIR_ARCH_X86_64) {
        /* always enable pae */
        def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;

        /* if vnuma is effective enable acpi */
        if (virDomainNumaGetNodeCount(def->numa) > 0)
            def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
    }

    /* add implicit balloon device */
    if (def->memballoon == NULL) {
        virDomainMemballoonDef *memballoon;
        memballoon = g_new0(virDomainMemballoonDef,
                            1);

        memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_XEN;
        def->memballoon = memballoon;
    }

    /* add implicit xenbus device */
    if (virDomainControllerFindByType(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS) == -1)
        if (virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS, -1, -1) == NULL)
            return -1;

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainCreateIfaceNames(virDomainDef *def, libxl_domain_config *d_config)
{
    size_t i;

    for (i = 0; i < def->nnets && i < d_config->num_nics; i++) {
        virDomainNetDef *net = def->nets[i];
        libxl_device_nic *x_nic = &d_config->nics[i];
        const char *suffix =
            x_nic->nictype != LIBXL_NIC_TYPE_VIF ? "-emu" : "";

        if (net->ifname)
            continue;

        net->ifname = g_strdup_printf(LIBXL_GENERATED_PREFIX_XEN "%d.%d%s",
                                      def->id, x_nic->devid, suffix);
    }
}

Project: libvirt
File: libxl_domain.c

libxlDomainCreateChannelPTY(virDomainDef *def, libxl_ctx *ctx)
{
    libxl_device_channel *x_channels;
    virDomainChrDef *chr;
    size_t i;
    int nchannels;

    x_channels = libxl_device_channel_list(ctx, def->id, &nchannels);
    if (!x_channels)
        return;

    for (i = 0; i < def->nchannels; i++) {
        libxl_channelinfo channelinfo;
        int ret;

        chr = def->channels[i];
        if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY)
            continue;

        ret = libxl_device_channel_getinfo(ctx, def->id, &x_channels[i],
                                           &channelinfo);

        if (!ret && channelinfo.u.pty.path &&
            *channelinfo.u.pty.path != '\0') {
                VIR_FREE(chr->source->data.file.path);
                chr->source->data.file.path = g_strdup(channelinfo.u.pty.path);
            }
    }

    for (i = 0; i < nchannels; i++)
        libxl_device_channel_dispose(&x_channels[i]);
}

Project: libvirt
File: libxl_domain.c

libxlDomainShutdownHandleDestroy(libxlDriverPrivate *driver,
                                 virDomainObj *vm)
{
    libxlDomainDestroyInternal(driver, vm);
    libxlDomainCleanup(driver, vm);
    if (!vm->persistent)
        virDomainObjListRemove(driver->domains, vm);
}

Project: libvirt
File: libxl_domain.c

libxlDomainSaveImageOpen(libxlDriverPrivate *driver,
                         const char *from,
                         virDomainDef **ret_def,
                         libxlSavefileHeader *ret_hdr)
{
    int fd;
    virDomainDef *def = NULL;
    libxlSavefileHeader hdr;
    g_autofree char *xml = NULL;

    if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
        virReportSystemError(-fd,
                             _("Failed to open domain image file '%s'"), from);
        goto error;
    }

    if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read libxl header"));
        goto error;
    }

    if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) {
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect"));
        goto error;
    }

    if (hdr.version > LIBXL_SAVE_VERSION) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
                       hdr.version, LIBXL_SAVE_VERSION);
        goto error;
    }

    if (hdr.xmlLen <= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), hdr.xmlLen);
        goto error;
    }

    xml = g_new0(char, hdr.xmlLen);

    if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML"));
        goto error;
    }

    if (!(def = virDomainDefParseString(xml, driver->xmlopt, NULL,
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                        VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
        goto error;

    *ret_def = def;
    *ret_hdr = hdr;

    return fd;

 error:
    virDomainDefFree(def);
    VIR_FORCE_CLOSE(fd);
    return -1;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjBeginJob(libxlDriverPrivate *driver G_GNUC_UNUSED,
                       virDomainObj *obj,
                       enum libxlDomainJob job)
{
    libxlDomainObjPrivate *priv = obj->privateData;
    unsigned long long now;
    unsigned long long then;

    if (virTimeMillisNow(&now) < 0)
        return -1;
    then = now + LIBXL_JOB_WAIT_TIME;

    while (priv->job.active) {
        VIR_DEBUG("Wait normal job condition for starting job: %s",
                  libxlDomainJobTypeToString(job));
        if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
            goto error;
    }

    libxlDomainObjResetJob(priv);

    VIR_DEBUG("Starting job: %s", libxlDomainJobTypeToString(job));
    priv->job.active = job;
    priv->job.owner = virThreadSelfID();
    priv->job.started = now;
    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;

    return 0;

 error:
    VIR_WARN("Cannot start job (%s) for domain %s;"
             " current job is (%s) owned by (%d)",
             libxlDomainJobTypeToString(job),
             obj->def->name,
             libxlDomainJobTypeToString(priv->job.active),
             priv->job.owner);

    if (errno == ETIMEDOUT)
        virReportError(VIR_ERR_OPERATION_TIMEOUT,
                       "%s", _("cannot acquire state change lock"));
    else
        virReportSystemError(errno,
                             "%s", _("cannot acquire job mutex"));

    return -1;
}

Project: libvirt
File: libxl_domain.c

libxlDomainDestroyInternal(libxlDriverPrivate *driver,
                           virDomainObj *vm)
{
    g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
    libxlDomainObjPrivate *priv = vm->privateData;
    int ret = -1;

    if (priv->deathW) {
        libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
        priv->deathW = NULL;
    }

    /* Unlock virDomainObj during destroy, which can take considerable
     * time on large memory domains.
     */
    virObjectUnlock(vm);
    ret = libxl_domain_destroy(cfg->ctx, vm->def->id, NULL);
    virObjectLock(vm);

    return ret;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
                              virDomainObj *vm,
                              virDomainDefParserConfig *config G_GNUC_UNUSED)
{
    libxlDomainObjPrivate *priv = vm->privateData;

    priv->lockState = virXPathString("string(./lockstate)", ctxt);

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainStartRestore(libxlDriverPrivate *driver,
                        virDomainObj *vm,
                        bool start_paused,
                        int restore_fd,
                        uint32_t restore_ver)
{
    return libxlDomainStart(driver, vm, start_paused,
                            restore_fd, restore_ver);
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjEndJob(libxlDriverPrivate *driver G_GNUC_UNUSED,
                     virDomainObj *obj)
{
    libxlDomainObjPrivate *priv = obj->privateData;
    enum libxlDomainJob job = priv->job.active;

    VIR_DEBUG("Stopping job: %s",
              libxlDomainJobTypeToString(job));

    libxlDomainObjResetJob(priv);
    virCondSignal(&priv->job.cond);
}

Project: libvirt
File: libxl_domain.c

libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,
                             void **data)
{
    libxlDomainXmlNsDef *nsdata = NULL;
    g_autofree xmlNodePtr *nodes = NULL;
    ssize_t nnodes;
    size_t i;
    int ret = -1;

    if ((nnodes = virXPathNodeSet("./xen:commandline/xen:arg", ctxt, &nodes)) < 0)
        return -1;

    if (nnodes == 0)
        return 0;

    nsdata = g_new0(libxlDomainXmlNsDef, 1);
    nsdata->args = g_new0(char *, nnodes + 1);

    for (i = 0; i < nnodes; i++) {
        if (!(nsdata->args[nsdata->num_args++] = virXMLPropString(nodes[i], "value"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No device model command-line argument specified"));
            goto cleanup;
        }
    }

    *data = g_steal_pointer(&nsdata);
    ret = 0;

 cleanup:
    libxlDomainDefNamespaceFree(nsdata);
    return ret;
}

Project: libvirt
File: libxl_domain.c

libxlDomainDefValidate(const virDomainDef *def,
                       void *opaque,
                       void *parseOpaque G_GNUC_UNUSED)
{
    libxlDriverPrivate *driver = opaque;
    g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
    bool reqSecureBoot = false;

    if (!virCapabilitiesDomainSupported(cfg->caps, def->os.type,
                                        def->os.arch,
                                        def->virtType))
        return -1;

    /* Xen+ovmf does not support secure boot */
    if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI) {
        if (def->os.firmwareFeatures &&
            def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE_BOOT])
            reqSecureBoot = true;
    }
    if (virDomainDefHasOldStyleUEFI(def)) {
        if (def->os.loader &&
            def->os.loader->secure == VIR_TRISTATE_BOOL_YES)
            reqSecureBoot = true;
    }
    if (reqSecureBoot) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Secure boot is not supported on Xen"));
        return -1;
    }

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlNetworkUnwindDevices(virDomainDef *def)
{
    if (def->nnets) {
        size_t i;

        for (i = 0; i < def->nnets; i++) {
            virDomainNetDef *net = def->nets[i];

            if (net->ifname &&
                STRPREFIX(net->ifname, LIBXL_GENERATED_PREFIX_XEN))
                VIR_FREE(net->ifname);

            /* cleanup actual device */
            virDomainNetRemoveHostdev(def, net);
            if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
                g_autoptr(virConnect) conn = virGetConnectNetwork();

                if (conn)
                    virDomainNetReleaseActualDevice(conn, def, net);
                else
                    VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
            }
        }
    }
}

Project: libvirt
File: libxl_domain.c

libxlDomainAutoCoreDump(libxlDriverPrivate *driver,
                        virDomainObj *vm)
{
    g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
    g_autoptr(GDateTime) now = g_date_time_new_now_local();
    g_autofree char *nowstr = NULL;
    g_autofree char *dumpfile = NULL;

    nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S");

    dumpfile = g_strdup_printf("%s/%s-%s", cfg->autoDumpDir, vm->def->name,
                               nowstr);

    /* Unlock virDomainObj while dumping core */
    virObjectUnlock(vm);
    libxl_domain_core_dump(cfg->ctx, vm->def->id, dumpfile, NULL);
    virObjectLock(vm);

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainStartPerform(libxlDriverPrivate *driver,
                        virDomainObj *vm,
                        bool start_paused,
                        int restore_fd,
                        uint32_t restore_ver)
{
    libxl_domain_config d_config;
    int ret = -1;
    int libxlret = -1;
    uint32_t domid = 0;
    g_autofree char *dom_xml = NULL;
    libxlDomainObjPrivate *priv = vm->privateData;
    g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
    libxl_asyncprogress_how aop_console_how;
    libxl_domain_restore_params params;
    g_autofree char *config_json = NULL;

    libxl_domain_config_init(&d_config);

    if (libxlBuildDomainConfig(driver->reservedGraphicsPorts, vm->def,
                               cfg, &d_config) < 0)
        goto cleanup;

    if (cfg->autoballoon && libxlDomainFreeMem(cfg->ctx, &d_config) < 0)
        goto cleanup;

    /* now that we know it is about to start call the hook if present */
    if (libxlDomainHookRun(driver, vm->def, 0,
                           VIR_HOOK_LIBXL_OP_START,
                           VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
        goto cleanup;

    if (priv->hookRun) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(vm->def->uuid, uuidstr);

        VIR_WARN("Domain id='%d' name='%s' uuid='%s' is tainted: hook",
                 vm->def->id,
                 vm->def->name,
                 uuidstr);
    }

    /* Unlock virDomainObj while creating the domain */
    virObjectUnlock(vm);

    aop_console_how.for_callback = vm;
    aop_console_how.callback = libxlConsoleCallback;
    if (restore_fd < 0) {
        libxlret = libxl_domain_create_new(cfg->ctx, &d_config,
                                      &domid, NULL, &aop_console_how);
    } else {
        libxl_domain_restore_params_init(&params);
        params.stream_version = restore_ver;
        libxlret = libxlDomainCreateRestoreWrapper(cfg->ctx, &d_config, &domid,
                                              restore_fd, &params,
                                          &aop_console_how);
        libxl_domain_restore_params_dispose(&params);
    }
    virObjectLock(vm);

    if (libxlret) {
        if (restore_fd < 0)
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("libxenlight failed to create new domain '%s'"),
                           d_config.c_info.name);
        else
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("libxenlight failed to restore domain '%s'"),
                           d_config.c_info.name);
        goto cleanup;
    }

    /*
     * The domain has been successfully created with libxl, so it should
     * be cleaned up if there are any subsequent failures.
     */
    vm->def->id = domid;
    config_json = libxl_domain_config_to_json(cfg->ctx, &d_config);

    libxlLoggerOpenFile(cfg->logger, domid, vm->def->name, config_json);

    if (virDomainLockProcessResume(driver->lockManager,
                                  "xen:///system",
                                  vm,
                                  priv->lockState) < 0)
        goto destroy_dom;
    VIR_FREE(priv->lockState);
    priv->lockProcessRunning = true;

    /* Always enable domain death events */
    if (libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW))
        goto destroy_dom;

    libxlDomainCreateIfaceNames(vm->def, &d_config);
    libxlDomainUpdateDiskParams(vm->def, cfg->ctx);

    if (vm->def->nchannels > 0)
        libxlDomainCreateChannelPTY(vm->def, cfg->ctx);

    if ((dom_xml = virDomainDefFormat(vm->def, driver->xmlopt, 0)) == NULL)
        goto destroy_dom;

    if (libxl_userdata_store(cfg->ctx, domid, "libvirt-xml",
                             (uint8_t *)dom_xml, strlen(dom_xml) + 1)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to store userdata"));
        goto destroy_dom;
    }

    if (!start_paused) {
        libxlDomainUnpauseWrapper(cfg->ctx, domid);
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
    } else {
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
    }

    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
        goto destroy_dom;

    /* finally we can call the 'started' hook script if any */
    if (libxlDomainHookRun(driver, vm->def, 0,
                           VIR_HOOK_LIBXL_OP_STARTED,
                           VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
        goto destroy_dom;

    ret = 0;
    goto cleanup;

 destroy_dom:
    libxlDomainDestroyInternal(driver, vm);
    vm->def->id = -1;
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);

 cleanup:
    libxl_domain_config_dispose(&d_config);
    return ret;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjResetJob(libxlDomainObjPrivate *priv)
{
    struct libxlDomainJobObj *job = &priv->job;

    job->active = LIBXL_JOB_NONE;
    job->owner = 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainFreeMem(libxl_ctx *ctx, libxl_domain_config *d_config)
{
    uint64_t needed_mem;
    uint64_t free_mem;
    uint64_t target_mem;
    int tries = 3;
    int wait_secs = 10;

    if (libxlDomainNeedMemoryWrapper(ctx, d_config, &needed_mem) < 0)
        goto error;

    do {
        if (libxlGetFreeMemoryWrapper(ctx, &free_mem) < 0)
            goto error;

        if (free_mem >= needed_mem)
            return 0;

        target_mem = free_mem - needed_mem;
        if (libxlSetMemoryTargetWrapper(ctx, 0, target_mem,
                                        /* relative */ 1, 0) < 0)
            goto error;

        if (libxl_wait_for_memory_target(ctx, 0, wait_secs) < 0)
            goto error;

        tries--;
    } while (tries > 0);

 error:
    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                   _("Failed to balloon domain0 memory"));
    return -1;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjPrivateFree(void *data)
{
    libxlDomainObjPrivate *priv = data;

    g_free(priv->lockState);
    libxlDomainObjFreeJob(priv);
    virChrdevFree(priv->devs);
    g_free(priv);
}

Project: libvirt
File: libxl_domain.c

libxlDomainDefCheckABIStability(libxlDriverPrivate *driver,
                                virDomainDef *src,
                                virDomainDef *dst)
{
    virDomainDef *migratableDefSrc = NULL;
    virDomainDef *migratableDefDst = NULL;
    bool ret = false;

    if (!(migratableDefSrc = virDomainDefCopy(src, driver->xmlopt, NULL, true)) ||
        !(migratableDefDst = virDomainDefCopy(dst, driver->xmlopt, NULL, true)))
        goto cleanup;

    ret = virDomainDefCheckABIStability(migratableDefSrc,
                                        migratableDefDst,
                                        driver->xmlopt);

 cleanup:
    virDomainDefFree(migratableDefSrc);
    virDomainDefFree(migratableDefDst);
    return ret;
}

Project: libvirt
File: libxl_domain.c

libxlDomainJobUpdateTime(struct libxlDomainJobObj *job)
{
    virDomainJobInfoPtr jobInfo = job->current;
    unsigned long long now;

    if (!job->started)
        return 0;

    if (virTimeMillisNow(&now) < 0)
        return -1;

    if (now < job->started) {
        job->started = 0;
        return 0;
    }

    jobInfo->timeElapsed = now - job->started;
    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainDefNamespaceFree(void *nsdata)
{
    libxlDomainXmlNsDef *def = nsdata;

    if (!def)
        return;

    g_strfreev(def->args);
    g_free(def);
}

Project: libvirt
File: libxl_domain.c

libxlDomainShutdownHandleRestart(libxlDriverPrivate *driver,
                                 virDomainObj *vm)
{
    libxlDomainDestroyInternal(driver, vm);
    libxlDomainCleanup(driver, vm);
    if (libxlDomainStartNew(driver, vm, false) < 0) {
        VIR_ERROR(_("Failed to restart VM '%s': %s"),
                  vm->def->name, virGetLastErrorMessage());
    }
}

Project: libvirt
File: libxl_domain.c

libxlDomainUpdateDiskParams(virDomainDef *def, libxl_ctx *ctx)
{
    libxl_device_disk *disks;
    int num_disks = 0;
    size_t i;
    int idx;

    disks = libxl_device_disk_list(ctx, def->id, &num_disks);
    if (!disks)
        return;

    for (i = 0; i < num_disks; i++) {
        if ((idx = virDomainDiskIndexByName(def, disks[i].vdev, false)) < 0)
            continue;

        libxlUpdateDiskDef(def->disks[idx], &disks[i]);
    }

    for (i = 0; i < num_disks; i++)
        libxl_device_disk_dispose(&disks[i]);
    VIR_FREE(disks);
}

Project: libvirt
File: libxl_domain.c

libxlDomainStartNew(libxlDriverPrivate *driver,
            virDomainObj *vm,
            bool start_paused)
{
    g_autofree char *managed_save_path = NULL;
    int restore_fd = -1;
    virDomainDef *def = NULL;
    libxlSavefileHeader hdr;
    uint32_t restore_ver = LIBXL_SAVE_VERSION;
    int ret = -1;

    /* If there is a managed saved state restore it instead of starting
     * from scratch. The old state is removed once the restoring succeeded. */
    managed_save_path = libxlDomainManagedSavePath(driver, vm);
    if (managed_save_path == NULL)
        return -1;

    if (virFileExists(managed_save_path)) {
        restore_fd = libxlDomainSaveImageOpen(driver, managed_save_path,
                                              &def, &hdr);
        if (restore_fd < 0)
            goto cleanup;

        restore_ver = hdr.version;

        if (STRNEQ(vm->def->name, def->name) ||
            memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
            char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
            char def_uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, vm_uuidstr);
            virUUIDFormat(def->uuid, def_uuidstr);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("cannot restore domain '%s' uuid %s from a file which belongs to domain '%s' uuid %s"),
                           vm->def->name, vm_uuidstr, def->name, def_uuidstr);
            goto cleanup;
        }

        virDomainObjAssignDef(vm, &def, true, NULL);

        if (unlink(managed_save_path) < 0)
            VIR_WARN("Failed to remove the managed state %s",
                     managed_save_path);

        vm->hasManagedSave = false;
    }

    ret = libxlDomainStart(driver, vm, start_paused, restore_fd, restore_ver);

 cleanup:
    virDomainDefFree(def);
    VIR_FORCE_CLOSE(restore_fd);
    return ret;
}

Project: libvirt
File: libxl_domain.c

libxlDomainStartPrepare(libxlDriverPrivate *driver,
                        virDomainObj *vm)
{
    virHostdevManager *hostdev_mgr = driver->hostdevMgr;
    unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI | VIR_HOSTDEV_SP_USB;

    if (virDomainObjSetDefTransient(driver->xmlopt, vm, NULL) < 0)
        return -1;

    /* Run an early hook to set-up missing devices */
    if (libxlDomainHookRun(driver, vm->def, 0,
                           VIR_HOOK_LIBXL_OP_PREPARE,
                           VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
        goto error;

    if (virDomainLockProcessStart(driver->lockManager,
                                  "xen:///system",
                                  vm,
                                  true,
                                  NULL) < 0)
        goto error;

    if (libxlNetworkPrepareDevices(vm->def) < 0)
        goto error;

    if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
                                       vm->def, hostdev_flags) < 0)
        goto error;

    return 0;

 error:
    libxlNetworkUnwindDevices(vm->def);
    virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
                                    vm->def, hostdev_flags);
    virDomainObjRemoveTransientDef(vm);
    return -1;
}

Project: libvirt
File: libxl_domain.c

libxlNetworkPrepareDevices(virDomainDef *def)
{
    size_t i;
    g_autoptr(virConnect) conn = NULL;

    for (i = 0; i < def->nnets; i++) {
        virDomainNetDef *net = def->nets[i];
        virDomainNetType actualType;

        /* If appropriate, grab a physical device from the configured
         * network's pool of devices, or resolve bridge device name
         * to the one defined in the network definition.
         */
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            if (!conn && !(conn = virGetConnectNetwork()))
                return -1;
            if (virDomainNetAllocateActualDevice(conn, def, net) < 0)
                return -1;
        }

        /* final validation now that actual type is known */
        if (virDomainActualNetDefValidate(net) < 0)
            return -1;

        actualType = virDomainNetGetActualType(net);
        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
            net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            /* Each type='hostdev' network device must also have a
             * corresponding entry in the hostdevs array. For netdevs
             * that are hardcoded as type='hostdev', this is already
             * done by the parser, but for those allocated from a
             * network / determined at runtime, we need to do it
             * separately.
             */
            virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net);
            virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci;

            if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
                hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
                pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;

            if (virDomainHostdevInsert(def, hostdev) < 0)
                return -1;
        }
    }

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjInitJob(libxlDomainObjPrivate *priv)
{
    memset(&priv->job, 0, sizeof(priv->job));

    if (virCondInit(&priv->job.cond) < 0)
        return -1;

    priv->job.current = g_new0(virDomainJobInfo, 1);

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainHookRun(libxlDriverPrivate *driver,
                   virDomainDef *def,
                   unsigned int def_fmtflags,
                   int hookop,
                   int hooksubop,
                   char **output)
{
    g_autofree char *xml = NULL;

    if (!virHookPresent(VIR_HOOK_DRIVER_LIBXL))
        return 0;

    xml = virDomainDefFormat(def, driver->xmlopt, def_fmtflags);
    return virHookCall(VIR_HOOK_DRIVER_LIBXL, def->name,
                       hookop, hooksubop,
                       NULL, xml, output);
}

Project: libvirt
File: libxl_domain.c

libxlDomainCleanup(libxlDriverPrivate *driver,
                   virDomainObj *vm)
{
    libxlDomainObjPrivate *priv = vm->privateData;
    g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
    int vnc_port;
    char *file;
    virHostdevManager *hostdev_mgr = driver->hostdevMgr;
    unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;

    VIR_DEBUG("Cleaning up domain with id '%d' and name '%s'",
              vm->def->id, vm->def->name);

    hostdev_flags |= VIR_HOSTDEV_SP_USB;

    /* Call hook with stopped operation. Ignore error and continue with cleanup */
    ignore_value(libxlDomainHookRun(driver, vm->def, 0,
                                    VIR_HOOK_LIBXL_OP_STOPPED,
                                    VIR_HOOK_SUBOP_END, NULL));

    virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
                                    vm->def, hostdev_flags);

    if (priv->lockProcessRunning) {
        VIR_FREE(priv->lockState);
        if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
            VIR_WARN("Unable to release lease on %s", vm->def->name);
        else
            priv->lockProcessRunning = false;
        VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
    }

    libxlLoggerCloseFile(cfg->logger, vm->def->id);
    vm->def->id = -1;

    if (priv->deathW) {
        libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
        priv->deathW = NULL;
    }

    if (!!g_atomic_int_dec_and_test(&driver->nactive) && driver->inhibitCallback)
        driver->inhibitCallback(false, driver->inhibitOpaque);

    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport) {
        vnc_port = vm->def->graphics[0]->data.vnc.port;
        if (vnc_port >= LIBXL_VNC_PORT_MIN) {
            if (virPortAllocatorRelease(vnc_port) < 0)
                VIR_DEBUG("Could not mark port %d as unused", vnc_port);
        }
    }

    libxlNetworkUnwindDevices(vm->def);

    file = g_strdup_printf("%s/%s.xml", cfg->stateDir, vm->def->name);
    if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
        VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name);
    VIR_FREE(file);

    /* Call hook with release operation. Ignore error and continue with cleanup */
    ignore_value(libxlDomainHookRun(driver, vm->def, 0,
                                    VIR_HOOK_LIBXL_OP_RELEASE,
                                    VIR_HOOK_SUBOP_END, NULL));

    virDomainObjRemoveTransientDef(vm);
}

Project: libvirt
File: libxl_domain.c

libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev,
                              const virDomainDef *def,
                              unsigned int parseFlags G_GNUC_UNUSED,
                              void *opaque G_GNUC_UNUSED,
                              void *parseOpaque G_GNUC_UNUSED)
{
    if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
        dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE &&
        def->os.type != VIR_DOMAIN_OSTYPE_HVM)
        dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;

    if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV ||
        (dev->type == VIR_DOMAIN_DEVICE_NET &&
         dev->data.net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) {

        virDomainHostdevDef *hostdev;
        virDomainHostdevSubsysPCI *pcisrc;

        if (dev->type == VIR_DOMAIN_DEVICE_NET)
            hostdev = &dev->data.net->data.hostdev.def;
        else
            hostdev = dev->data.hostdev;
        pcisrc = &hostdev->source.subsys.u.pci;

        /* forbid capabilities mode hostdev in this kind of hypervisor */
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("hostdev mode 'capabilities' is not "
                             "supported in %s"),
                           virDomainVirtTypeToString(def->virtType));
            return -1;
        }

        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
            pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)
            pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
    }

    if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) {
        if (dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT) {
            if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
                def->os.type == VIR_DOMAIN_OSTYPE_LINUX)
                dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
            else if (ARCH_IS_PPC64(def->os.arch))
                dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VGA;
            else
                dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
        }

        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
            int dm_type = libxlDomainGetEmulatorType(def);

            switch (dev->data.video->type) {
                case VIR_DOMAIN_VIDEO_TYPE_VGA:
                case VIR_DOMAIN_VIDEO_TYPE_XEN:
                    if (dev->data.video->vram == 0) {
                        if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
                            dev->data.video->vram = 16 * 1024;
                        else
                            dev->data.video->vram = 8 * 1024;
                    }
                    break;
                case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
                    if (dev->data.video->vram == 0) {
                        if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
                            dev->data.video->vram = 8 * 1024;
                        else
                            dev->data.video->vram = 4 * 1024;
                    }
                    break;
                case VIR_DOMAIN_VIDEO_TYPE_QXL:
                    if (dev->data.video->vram == 0)
                        dev->data.video->vram = 128 * 1024;
                    break;
            }
        }
    }

    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
        virDomainDiskDef *disk = dev->data.disk;
        int actual_type = virStorageSourceGetActualType(disk->src);
        int format = virDomainDiskGetFormat(disk);

        /* for network-based disks, set 'qemu' as the default driver */
        if (actual_type == VIR_STORAGE_TYPE_NETWORK) {
            if (!virDomainDiskGetDriver(disk))
                virDomainDiskSetDriver(disk, "qemu");
        }

        /* xl.cfg default format is raw. See xl-disk-configuration(5) */
        if (format == VIR_STORAGE_FILE_NONE)
            virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
    }

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjFreeJob(libxlDomainObjPrivate *priv)
{
    ignore_value(virCondDestroy(&priv->job.cond));
    VIR_FREE(priv->job.current);
}

Project: libvirt
File: libxl_domain.c

libxlDomainDefNamespaceFormatXML(virBuffer *buf,
                                 void *nsdata)
{
    libxlDomainXmlNsDef *cmd = nsdata;
    size_t i;

    if (!cmd->num_args)
        return 0;

    virBufferAddLit(buf, "<xen:commandline>\n");
    virBufferAdjustIndent(buf, 2);

    for (i = 0; i < cmd->num_args; i++)
        virBufferEscapeString(buf, "<xen:arg value='%s'/>\n",
                              cmd->args[i]);

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</xen:commandline>\n");

    return 0;
}

Project: libvirt
File: libxl_domain.c

libxlDomainObjPrivateXMLFormat(virBuffer *buf,
                               virDomainObj *vm)
{
    libxlDomainObjPrivate *priv = vm->privateData;

    if (priv->lockState)
        virBufferAsprintf(buf, "<lockstate>%s</lockstate>\n", priv->lockState);

    return 0;
}