diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c index 8b67e511e2..1c11eacb9d 100644 --- a/src/conf/storage_source_conf.c +++ b/src/conf/storage_source_conf.c @@ -886,6 +886,9 @@ virStorageSourceCopy(const virStorageSource *src, return NULL; } + if (src->fdtuple) + def->fdtuple = g_object_ref(src->fdtuple); + /* ssh config passthrough for libguestfs */ def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled; def->ssh_user = g_strdup(src->ssh_user); @@ -1170,6 +1173,8 @@ virStorageSourceClear(virStorageSource *def) virStorageSourceInitiatorClear(&def->initiator); + g_clear_pointer(&def->fdtuple, g_object_unref); + /* clear everything except the class header as the object APIs * will break otherwise */ memset((char *) def + sizeof(def->parent), 0, diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h index 9c07eef200..f981261ff4 100644 --- a/src/conf/storage_source_conf.h +++ b/src/conf/storage_source_conf.h @@ -415,6 +415,8 @@ struct _virStorageSource { * registered with a full index (vda[3]) so that we can properly report just * one event for it */ bool thresholdEventWithIndex; + + virStorageSourceFDTuple *fdtuple; }; G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index e6cbd4c0cb..9fd3c39646 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -874,6 +874,7 @@ qemuDomainStorageSourcePrivateDispose(void *obj) g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree); g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree); g_clear_pointer(&priv->tlsKeySecret, qemuDomainSecretInfoFree); + g_clear_pointer(&priv->fdpass, qemuFDPassFree); } @@ -10824,6 +10825,61 @@ qemuDomainPrepareDiskSourceLegacy(virDomainDiskDef *disk, } +static int +qemuDomainPrepareStorageSourceFDs(virStorageSource *src, + qemuDomainObjPrivate *priv) +{ + qemuDomainStorageSourcePrivate *srcpriv = NULL; + virStorageType actualType = virStorageSourceGetActualType(src); + virStorageSourceFDTuple *fdt = NULL; + size_t i; + + if (actualType != VIR_STORAGE_TYPE_FILE && + actualType != VIR_STORAGE_TYPE_BLOCK) + return 0; + + if (!virStorageSourceIsFD(src)) + return 0; + + if (!(fdt = virHashLookup(priv->fds, src->fdgroup))) { + virReportError(VIR_ERR_INVALID_ARG, + _("file descriptor group '%s' was not associated with the domain"), + src->fdgroup); + return -1; + } + + srcpriv = qemuDomainStorageSourcePrivateFetch(src); + + srcpriv->fdpass = qemuFDPassNew(src->nodestorage, priv); + + for (i = 0; i < fdt->nfds; i++) { + g_autofree char *idx = g_strdup_printf("%zu", i); + int tmpfd; + + if (fdt->testfds) { + /* when testing we want to use stable FD numbers provided by the test + * case */ + tmpfd = dup2(fdt->fds[i], fdt->testfds[i]); + } else { + tmpfd = dup(fdt->fds[i]); + } + + if (tmpfd < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to duplicate file descriptor for fd group '%s'"), + src->fdgroup); + return -1; + } + + qemuFDPassAddFD(srcpriv->fdpass, &tmpfd, idx); + } + + src->fdtuple = g_object_ref(fdt); + + return 0; +} + + int qemuDomainPrepareStorageSourceBlockdevNodename(virDomainDiskDef *disk, virStorageSource *src, @@ -10861,6 +10917,9 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virDomainDiskDef *disk, if (qemuDomainPrepareStorageSourceNFS(src) < 0) return -1; + if (qemuDomainPrepareStorageSourceFDs(src, priv) < 0) + return -1; + return 0; } @@ -12213,6 +12272,28 @@ qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv) } +/** + * qemuDomainCleanupStorageSourceFD: + * @src: start of the chain to clear + * + * Cleans up the backing chain starting at @src of FD tuple structures for + * all FD-tuples which didn't request explicit relabelling and thus the struct + * is no longer needed. + */ +void +qemuDomainCleanupStorageSourceFD(virStorageSource *src) +{ + virStorageSource *n; + + for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) { + if (virStorageSourceIsFD(n) && n->fdtuple) { + if (!n->fdtuple->tryRestoreLabel) + g_clear_pointer(&n->fdtuple, g_object_unref); + } + } +} + + /** * qemuDomainStartupCleanup: * @@ -12222,5 +12303,10 @@ qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv) void qemuDomainStartupCleanup(virDomainObj *vm) { + size_t i; + qemuDomainSecretDestroy(vm); + + for (i = 0; i < vm->def->ndisks; i++) + qemuDomainCleanupStorageSourceFD(vm->def->disks[i]->src); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 11ef3e7b64..5114a311fb 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -305,6 +305,9 @@ struct _qemuDomainStorageSourcePrivate { /* key for decrypting TLS certificate */ qemuDomainSecretInfo *tlsKeySecret; + + /* file descriptors if user asks for FDs to be passed */ + qemuFDPass *fdpass; }; virObject *qemuDomainStorageSourcePrivateNew(void); @@ -925,6 +928,8 @@ int qemuDomainSecretChardevPrepare(virQEMUDriverConfig *cfg, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); +void qemuDomainCleanupStorageSourceFD(virStorageSource *src); + void qemuDomainStartupCleanup(virDomainObj *vm); int qemuDomainSecretPrepare(virQEMUDriver *driver, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 6e300f547c..dba699a8a8 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1016,6 +1016,7 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriver *driver, ignore_value(qemuHotplugRemoveManagedPR(vm, VIR_ASYNC_JOB_NONE)); } qemuDomainSecretDiskDestroy(disk); + qemuDomainCleanupStorageSourceFD(disk->src); return ret; }