void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { pciDeviceList *pcidevs; int i; if (!(pcidevs = qemuGetActivePciHostDeviceList(driver, hostdevs, nhostdevs))) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to allocate pciDeviceList: %s"), err ? err->message : _("unknown error")); virResetError(err); return; } /* Again 3 loops; mark all devices as inactive before reset * them and reset all the devices before re-attach */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciDevice *activeDev = NULL; /* Never delete the dev from list driver->activePciHostdevs * if it's used by other domain. */ activeDev = pciDeviceListFind(driver->activePciHostdevs, dev); if (activeDev && STRNEQ_NULLABLE(name, pciDeviceGetUsedBy(activeDev))) { pciDeviceListSteal(pcidevs, dev); continue; } /* pciDeviceListFree() will take care of freeing the dev. */ pciDeviceListSteal(driver->activePciHostdevs, dev); } for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciResetDevice(dev, driver->activePciHostdevs, driver->inactivePciHostdevs) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to reset PCI device: %s"), err ? err->message : _("unknown error")); virResetError(err); } } for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); qemuReattachPciDevice(dev, driver); } pciDeviceListFree(pcidevs); }
/** * virReleaseConnect: * @conn: the hypervisor connection to release * * Unconditionally release all memory associated with a connection. * The conn.lock mutex must be held prior to calling this, and will * be released prior to this returning. The connection obj must not * be used once this method returns. */ static void virReleaseConnect(virConnectPtr conn) { VIR_DEBUG("release connection %p", conn); /* make sure to release the connection lock before we call the * close callbacks, otherwise we will deadlock if an error * is raised by any of the callbacks */ virMutexUnlock(&conn->lock); if (conn->networkDriver) conn->networkDriver->close(conn); if (conn->interfaceDriver) conn->interfaceDriver->close(conn); if (conn->storageDriver) conn->storageDriver->close(conn); if (conn->deviceMonitor) conn->deviceMonitor->close(conn); if (conn->secretDriver) conn->secretDriver->close(conn); if (conn->nwfilterDriver) conn->nwfilterDriver->close(conn); if (conn->driver) conn->driver->close(conn); virMutexLock(&conn->lock); virResetError(&conn->err); virURIFree(conn->uri); virMutexUnlock(&conn->lock); virMutexDestroy(&conn->lock); VIR_FREE(conn); }
void qemuReattachPciDevice(pciDevice *dev, struct qemud_driver *driver) { int retries = 100; /* If the device is not managed and was attached to guest * successfully, it must have been inactive. */ if (!pciDeviceGetManaged(dev)) { if (pciDeviceListAdd(driver->inactivePciHostdevs, dev) < 0) pciFreeDevice(dev); return; } while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device") && retries) { usleep(100*1000); retries--; } if (pciReAttachDevice(dev, driver->activePciHostdevs, driver->inactivePciHostdevs) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to re-attach PCI device: %s"), err ? err->message : _("unknown error")); virResetError(err); } pciFreeDevice(dev); }
static void showError(virConnectPtr conn) { int ret; virErrorPtr err; err = malloc(sizeof(*err)); if (!err) { printf("Could not allocate memory for error data\n"); goto out; } ret = virConnCopyLastError(conn, err); switch (ret) { case 0: printf("No error found\n"); break; case -1: printf("Parameter error when attempting to get last error\n"); break; default: printf("libvirt reported: \"%s\"\n", err->message); break; } virResetError(err); free(err); out: return; }
/* * Internal helper to perform a deep copy of an error */ static int virCopyError(virErrorPtr from, virErrorPtr to) { int ret = 0; if (!to) return 0; virResetError(to); if (!from) return 0; to->code = from->code; to->domain = from->domain; to->level = from->level; if (VIR_STRDUP_QUIET(to->message, from->message) < 0) ret = -1; if (VIR_STRDUP_QUIET(to->str1, from->str1) < 0) ret = -1; if (VIR_STRDUP_QUIET(to->str2, from->str2) < 0) ret = -1; if (VIR_STRDUP_QUIET(to->str3, from->str3) < 0) ret = -1; to->int1 = from->int1; to->int2 = from->int2; /* * Deliberately not setting 'conn', 'dom', 'net' references */ return ret; }
/** * virResetLastError: * * Reset the last error caught at the library level. * * The error object is kept in thread local storage, so separate * threads can safely access this concurrently, only resetting * their own error object. */ void virResetLastError(void) { virErrorPtr err = virLastErrorObject(); if (err) virResetError(err); }
/* * Internal helper to perform a deep copy of the an error */ static int virCopyError(virErrorPtr from, virErrorPtr to) { int ret = 0; if (!to) return 0; virResetError(to); if (!from) return 0; to->code = from->code; to->domain = from->domain; to->level = from->level; if (from->message && !(to->message = strdup(from->message))) ret = -1; if (from->str1 && !(to->str1 = strdup(from->str1))) ret = -1; if (from->str2 && !(to->str2 = strdup(from->str2))) ret = -1; if (from->str3 && !(to->str3 = strdup(from->str3))) ret = -1; to->int1 = from->int1; to->int2 = from->int2; /* * Deliberately not setting 'conn', 'dom', 'net' references */ return ret; }
void virNetClientStreamDispose(void *obj) { virNetClientStreamPtr st = obj; virResetError(&st->err); VIR_FREE(st->incoming); virObjectUnref(st->prog); }
/** * virConnResetLastError: * @conn: pointer to the hypervisor connection * * The error object is kept in thread local storage, so separate * threads can safely access this concurrently. * * Reset the last error caught on that connection */ void virConnResetLastError(virConnectPtr conn) { if (conn == NULL) return; virObjectLock(conn); virResetError(&conn->err); virObjectUnlock(conn); }
void StoragePoolControlThread::sendConnErrors() { virtErrors = virConnGetLastError(currWorkConnect); if ( virtErrors!=NULL && virtErrors->code>0 ) { emit errorMsg( QString("VirtError(%1) : %2").arg(virtErrors->code) .arg(QString().fromUtf8(virtErrors->message)) ); virResetError(virtErrors); } else sendGlobalErrors(); }
/* * Internal helper that is called when a thread exits, to * release the error object stored in the thread local */ static void virLastErrFreeData(void *data) { virErrorPtr err = data; if (!err) return; virResetError(err); VIR_FREE(err); }
/** * virConnResetLastError: * @conn: pointer to the hypervisor connection * * The error object is kept in thread local storage, so separate * threads can safely access this concurrently. * * Reset the last error caught on that connection */ void virConnResetLastError(virConnectPtr conn) { if (conn == NULL) return; virMutexLock(&conn->lock); virResetError(&conn->err); virMutexUnlock(&conn->lock); }
int virNetClientStreamSetError(virNetClientStreamPtr st, virNetMessagePtr msg) { virNetMessageError err; int ret = -1; virObjectLock(st); if (st->err.code != VIR_ERR_OK) VIR_DEBUG("Overwriting existing stream error %s", NULLSTR(st->err.message)); virResetError(&st->err); memset(&err, 0, sizeof(err)); if (virNetMessageDecodePayload(msg, (xdrproc_t)xdr_virNetMessageError, &err) < 0) goto cleanup; if (err.domain == VIR_FROM_REMOTE && err.code == VIR_ERR_RPC && err.level == VIR_ERR_ERROR && err.message && STRPREFIX(*err.message, "unknown procedure")) { st->err.code = VIR_ERR_NO_SUPPORT; } else { st->err.code = err.code; } if (err.message) { st->err.message = *err.message; *err.message = NULL; } st->err.domain = err.domain; st->err.level = err.level; if (err.str1) { st->err.str1 = *err.str1; *err.str1 = NULL; } if (err.str2) { st->err.str2 = *err.str2; *err.str2 = NULL; } if (err.str3) { st->err.str3 = *err.str3; *err.str3 = NULL; } st->err.int1 = err.int1; st->err.int2 = err.int2; st->incomingEOF = true; virNetClientStreamEventTimerUpdate(st); ret = 0; cleanup: xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)&err); virObjectUnlock(st); return ret; }
static void qemuAgentDispose(void *obj) { qemuAgentPtr mon = obj; VIR_DEBUG("mon=%p", mon); if (mon->cb && mon->cb->destroy) (mon->cb->destroy)(mon, mon->vm); virCondDestroy(&mon->notify); VIR_FREE(mon->buffer); virResetError(&mon->lastError); }
int virSystemdTerminateMachine(const char *name) { int ret; DBusConnection *conn; virError error; if (!name) return 0; memset(&error, 0, sizeof(error)); if ((ret = virSystemdHasMachined()) < 0) goto cleanup; ret = -1; if (!(conn = virDBusGetSystemBus())) goto cleanup; /* * The systemd DBus API we're invoking has the * following signature * * TerminateMachine(in s name); * * @name a host unique name for the machine. shows up * in 'ps' listing & similar */ VIR_DEBUG("Attempting to terminate machine via systemd"); if (virDBusCallMethod(conn, NULL, &error, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "TerminateMachine", "s", name) < 0) goto cleanup; if (error.level == VIR_ERR_ERROR && STRNEQ_NULLABLE("org.freedesktop.machine1.NoSuchMachine", error.str1)) { virReportErrorObject(&error); goto cleanup; } ret = 0; cleanup: virResetError(&error); return ret; }
void VM_Viewer::sendConnErrors() { virtErrors = (NULL!=ptr_ConnPtr && *ptr_ConnPtr)? virConnGetLastError(*ptr_ConnPtr):NULL; if ( virtErrors!=NULL && virtErrors->code>0 ) { QString msg = QString("VirtError(%1) : %2").arg(virtErrors->code) .arg(QString().fromUtf8(virtErrors->message)); emit errorMsg( msg ); virResetError(virtErrors); } else sendGlobalErrors(); }
static void virConsoleDispose(void *obj) { virConsolePtr con = obj; if (con->st) virStreamFree(con->st); virCondDestroy(&con->cond); virResetError(&con->error); }
/** * virConnectDispose: * @obj: the hypervisor connection to release * * Unconditionally release all memory associated with a connection. * The connection object must not be used once this method returns. */ static void virConnectDispose(void *obj) { virConnectPtr conn = obj; if (conn->driver) conn->driver->connectClose(conn); virResetError(&conn->err); virURIFree(conn->uri); }
/** * virCopyLastError: * @to: target to receive the copy * * Copy the content of the last error caught at the library level * * The error object is kept in thread local storage, so separate * threads can safely access this concurrently. * * One will need to free the result with virResetError() * * Returns 0 if no error was found and the error code otherwise and -1 in case * of parameter error. */ int virCopyLastError(virErrorPtr to) { virErrorPtr err = virLastErrorObject(); /* We can't guarantee caller has initialized it to zero */ memset(to, 0, sizeof(*to)); if (err) virCopyError(err, to); else virResetError(to); return to->code; }
QString _VirtThread::sendConnErrors() { QString msg; virtErrors = (nullptr!=ptr_ConnPtr && *ptr_ConnPtr)? virConnGetLastError(*ptr_ConnPtr):nullptr; if ( virtErrors!=nullptr && virtErrors->code>0 ) { msg = QString("VirtError(%1) : %2").arg(virtErrors->code) .arg(QString().fromUtf8(virtErrors->message)); emit errorMsg( msg, number ); virResetError(virtErrors); } else msg = sendGlobalErrors(); return msg; }
/** * virConnCopyLastError: * @conn: pointer to the hypervisor connection * @to: target to receive the copy * * Copy the content of the last error caught on that connection * * This method is not protected against access from multiple * threads. In a multi-threaded application, always use the * global virGetLastError() API which is backed by thread * local storage. * * If the connection object was discovered to be invalid by * an API call, then the error will be reported against the * global error object. * * Since 0.6.0, all errors reported in the per-connection object * are also duplicated in the global error object. As such an * application can always use virGetLastError(). This method * remains for backwards compatibility. * * One will need to free the result with virResetError() * * Returns 0 if no error was found and the error code otherwise and -1 in case * of parameter error. */ int virConnCopyLastError(virConnectPtr conn, virErrorPtr to) { /* We can't guarantee caller has initialized it to zero */ memset(to, 0, sizeof(*to)); if (conn == NULL) return -1; virMutexLock(&conn->lock); if (conn->err.code == VIR_ERR_OK) virResetError(to); else virCopyError(&conn->err, to); virMutexUnlock(&conn->lock); return to->code; }
/** * virSetError: * @newerr: previously saved error object * * Set the current error from a previously saved error object * * Can be used to re-set an old error, which may have been squashed by * other functions (like cleanup routines). * * Returns 0 on success, -1 on failure. Leaves errno unchanged. */ int virSetError(virErrorPtr newerr) { virErrorPtr err; int saved_errno = errno; int ret = -1; err = virLastErrorObject(); if (!err) goto cleanup; virResetError(err); ret = virCopyError(newerr, err); cleanup: errno = saved_errno; return ret; }
void virNetClientStreamFree(virNetClientStreamPtr st) { virMutexLock(&st->lock); st->refs--; if (st->refs > 0) { virMutexUnlock(&st->lock); return; } virMutexUnlock(&st->lock); virResetError(&st->err); VIR_FREE(st->incoming); virMutexDestroy(&st->lock); virNetClientProgramFree(st->prog); VIR_FREE(st); }
/** * virCopyLastError: * @to: target to receive the copy * * Copy the content of the last error caught at the library level * * The error object is kept in thread local storage, so separate * threads can safely access this concurrently. * * One will need to free the result with virResetError() * * Returns error code or -1 in case of parameter error. */ int virCopyLastError(virErrorPtr to) { virErrorPtr err = virLastErrorObject(); if (!to) return -1; /* We can't guarantee caller has initialized it to zero */ memset(to, 0, sizeof(*to)); if (err) { virCopyError(err, to); } else { virResetError(to); to->code = VIR_ERR_NO_MEMORY; to->domain = VIR_FROM_NONE; to->level = VIR_ERR_ERROR; } return to->code; }
/** * virConnectDispose: * @conn: the hypervisor connection to release * * Unconditionally release all memory associated with a connection. * The conn.lock mutex must be held prior to calling this, and will * be released prior to this returning. The connection obj must not * be used once this method returns. */ static void virConnectDispose(void *obj) { virConnectPtr conn = obj; if (conn->networkDriver) conn->networkDriver->networkClose(conn); if (conn->interfaceDriver) conn->interfaceDriver->interfaceClose(conn); if (conn->storageDriver) conn->storageDriver->storageClose(conn); if (conn->nodeDeviceDriver) conn->nodeDeviceDriver->nodeDeviceClose(conn); if (conn->secretDriver) conn->secretDriver->secretClose(conn); if (conn->nwfilterDriver) conn->nwfilterDriver->nwfilterClose(conn); if (conn->driver) conn->driver->connectClose(conn); virMutexLock(&conn->lock); virResetError(&conn->err); virURIFree(conn->uri); if (conn->closeCallback) { virObjectLock(conn->closeCallback); conn->closeCallback->callback = NULL; virObjectUnlock(conn->closeCallback); virObjectUnref(conn->closeCallback); } virMutexUnlock(&conn->lock); virMutexDestroy(&conn->lock); }
int virSystemdTerminateMachine(const char *name, const char *drivername, bool privileged) { int ret; DBusConnection *conn; char *machinename = NULL; virError error; memset(&error, 0, sizeof(error)); ret = virDBusIsServiceEnabled("org.freedesktop.machine1"); if (ret < 0) goto cleanup; if ((ret = virDBusIsServiceRegistered("org.freedesktop.systemd1")) < 0) goto cleanup; ret = -1; if (!(conn = virDBusGetSystemBus())) goto cleanup; if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged))) goto cleanup; /* * The systemd DBus API we're invoking has the * following signature * * TerminateMachine(in s name); * * @name a host unique name for the machine. shows up * in 'ps' listing & similar */ VIR_DEBUG("Attempting to terminate machine via systemd"); if (virDBusCallMethod(conn, NULL, &error, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "TerminateMachine", "s", machinename) < 0) goto cleanup; if (error.code == VIR_ERR_ERROR && !STREQ_NULLABLE("org.freedesktop.machine1.NoSuchMachine", error.str1)) { virReportErrorObject(&error); goto cleanup; } ret = 0; cleanup: virResetError(&error); VIR_FREE(machinename); return ret; }
/** * virSystemdCreateMachine: * @name: driver unique name of the machine * @drivername: name of the virt driver * @privileged: whether driver is running privileged or per user * @uuid: globally unique UUID of the machine * @rootdir: root directory of machine filesystem * @pidleader: PID of the leader process * @iscontainer: true if a container, false if a VM * @nnicindexes: number of network interface indexes in list * @nicindexes: list of network interface indexes * @partition: name of the slice to place the machine in * * Returns 0 on success, -1 on fatal error, or -2 if systemd-machine is not available */ int virSystemdCreateMachine(const char *name, const char *drivername, bool privileged, const unsigned char *uuid, const char *rootdir, pid_t pidleader, bool iscontainer, size_t nnicindexes, int *nicindexes, const char *partition) { int ret; DBusConnection *conn; char *machinename = NULL; char *creatorname = NULL; char *slicename = NULL; static int hasCreateWithNetwork = 1; ret = virDBusIsServiceEnabled("org.freedesktop.machine1"); if (ret < 0) return ret; if ((ret = virDBusIsServiceRegistered("org.freedesktop.systemd1")) < 0) return ret; if (!(conn = virDBusGetSystemBus())) return -1; ret = -1; if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged))) goto cleanup; if (virAsprintf(&creatorname, "libvirt-%s", drivername) < 0) goto cleanup; if (partition) { if (!(slicename = virSystemdMakeSliceName(partition))) goto cleanup; } else { if (VIR_STRDUP(slicename, "") < 0) goto cleanup; } /* * The systemd DBus APIs we're invoking have the * following signature(s) * * CreateMachineWithNetwork(in s name, * in ay id, * in s service, * in s class, * in u leader, * in s root_directory, * in ai nicindexes * in a(sv) scope_properties, * out o path); * * CreateMachine(in s name, * in ay id, * in s service, * in s class, * in u leader, * in s root_directory, * in a(sv) scope_properties, * out o path); * * @name a host unique name for the machine. shows up * in 'ps' listing & similar * * @id: a UUID of the machine, ideally matching /etc/machine-id * for containers * * @service: identifier of the client ie "libvirt-lxc" * * @class: either the string "container" or "vm" depending * on the type of machine * * @leader: main PID of the machine, either the host emulator * process, or the 'init' PID of the container * * @root_directory: the root directory of the container, if * this is known & visible in the host filesystem, or empty string * * @nicindexes: list of network interface indexes for the * host end of the VETH device pairs. * * @scope_properties:an array (not a dict!) of properties that are * passed on to PID 1 when creating a scope unit for your machine. * Will allow initial settings for the cgroup & similar. * * @path: a bus path returned for the machine object created, to * allow further API calls to be made against the object. * */ VIR_DEBUG("Attempting to create machine via systemd"); if (virAtomicIntGet(&hasCreateWithNetwork)) { virError error; memset(&error, 0, sizeof(error)); if (virDBusCallMethod(conn, NULL, &error, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "CreateMachineWithNetwork", "sayssusa&ia(sv)", machinename, 16, uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15], creatorname, iscontainer ? "container" : "vm", (unsigned int)pidleader, rootdir ? rootdir : "", nnicindexes, nicindexes, 3, "Slice", "s", slicename, "After", "as", 1, "libvirtd.service", "Before", "as", 1, "libvirt-guests.service") < 0) goto cleanup; if (error.level == VIR_ERR_ERROR) { if (virDBusErrorIsUnknownMethod(&error)) { VIR_INFO("CreateMachineWithNetwork isn't supported, switching " "to legacy CreateMachine method for systemd-machined"); virResetError(&error); virAtomicIntSet(&hasCreateWithNetwork, 0); /* Could re-structure without Using goto, but this * avoids another atomic read which would trigger * another memory barrier */ goto fallback; } virReportErrorObject(&error); virResetError(&error); goto cleanup; } } else { fallback: if (virDBusCallMethod(conn, NULL, NULL, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "CreateMachine", "sayssusa(sv)", machinename, 16, uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15], creatorname, iscontainer ? "container" : "vm", (unsigned int)pidleader, rootdir ? rootdir : "", 3, "Slice", "s", slicename, "After", "as", 1, "libvirtd.service", "Before", "as", 1, "libvirt-guests.service") < 0) goto cleanup; } ret = 0; cleanup: VIR_FREE(creatorname); VIR_FREE(machinename); VIR_FREE(slicename); return ret; }
void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { pciDeviceList *pcidevs; int i; if (!(pcidevs = qemuGetActivePciHostDeviceList(driver, hostdevs, nhostdevs))) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to allocate pciDeviceList: %s"), err ? err->message : _("unknown error")); virResetError(err); return; } /* Again 4 loops; mark all devices as inactive before reset * them and reset all the devices before re-attach. * Attach mac and port profile parameters to devices */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciDevice *activeDev = NULL; /* Never delete the dev from list driver->activePciHostdevs * if it's used by other domain. */ activeDev = pciDeviceListFind(driver->activePciHostdevs, dev); if (activeDev && STRNEQ_NULLABLE(name, pciDeviceGetUsedBy(activeDev))) { pciDeviceListSteal(pcidevs, dev); continue; } /* pciDeviceListFree() will take care of freeing the dev. */ pciDeviceListSteal(driver->activePciHostdevs, dev); } /* * For SRIOV net host devices, unset mac and port profile before * reset and reattach device */ for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) { qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir); } } for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciResetDevice(dev, driver->activePciHostdevs, driver->inactivePciHostdevs) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to reset PCI device: %s"), err ? err->message : _("unknown error")); virResetError(err); } } while (pciDeviceListCount(pcidevs) > 0) { pciDevice *dev = pciDeviceListStealIndex(pcidevs, 0); qemuReattachPciDevice(dev, driver); } pciDeviceListFree(pcidevs); }
void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { virPCIDeviceListPtr pcidevs; size_t i; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virObjectLock(driver->activePciHostdevs); virObjectLock(driver->inactivePciHostdevs); if (!(pcidevs = qemuGetActivePciHostDeviceList(driver, hostdevs, nhostdevs))) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to allocate PCI device list: %s"), err ? err->message : _("unknown error")); virResetError(err); goto cleanup; } /* Again 4 loops; mark all devices as inactive before reset * them and reset all the devices before re-attach. * Attach mac and port profile parameters to devices */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); virPCIDevicePtr activeDev = NULL; /* delete the copy of the dev from pcidevs if it's used by * other domain. Or delete it from activePciHostDevs if it had * been used by this domain. */ activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev); if (activeDev && STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) { virPCIDeviceListDel(pcidevs, dev); continue; } virPCIDeviceListDel(driver->activePciHostdevs, dev); } /* At this point, any device that had been used by the guest is in * pcidevs, but has been removed from activePciHostdevs. */ /* * For SRIOV net host devices, unset mac and port profile before * reset and reattach device */ for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) { qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir); } } for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); if (virPCIDeviceReset(dev, driver->activePciHostdevs, driver->inactivePciHostdevs) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to reset PCI device: %s"), err ? err->message : _("unknown error")); virResetError(err); } } while (virPCIDeviceListCount(pcidevs) > 0) { virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0); qemuReattachPciDevice(dev, driver); } virObjectUnref(pcidevs); cleanup: virObjectUnlock(driver->activePciHostdevs); virObjectUnlock(driver->inactivePciHostdevs); virObjectUnref(cfg); }
/** * virFreeError: * @err: error to free * * Resets and frees the given error. */ void virFreeError(virErrorPtr err) { virResetError(err); VIR_FREE(err); }