qemu: Prepare data for FD-passed disk image sources

When starting up a VM with FD-passed images we need to look up the
corresponding named FD set and associate it with the virStorageSource
based on the name.

The association is brought into virStorageSource as security labelling
code will need to access the FD to perform selinux labelling.

Similarly when startup is complete in certain cases we no longer need to
keep the copy of FDs and thus can close them.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
Peter Krempa 2022-05-04 15:00:18 +02:00
parent 47b922f3f8
commit 81cbfc2fc3
5 changed files with 99 additions and 0 deletions

View File

@ -886,6 +886,9 @@ virStorageSourceCopy(const virStorageSource *src,
return NULL; return NULL;
} }
if (src->fdtuple)
def->fdtuple = g_object_ref(src->fdtuple);
/* ssh config passthrough for libguestfs */ /* ssh config passthrough for libguestfs */
def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled; def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled;
def->ssh_user = g_strdup(src->ssh_user); def->ssh_user = g_strdup(src->ssh_user);
@ -1170,6 +1173,8 @@ virStorageSourceClear(virStorageSource *def)
virStorageSourceInitiatorClear(&def->initiator); virStorageSourceInitiatorClear(&def->initiator);
g_clear_pointer(&def->fdtuple, g_object_unref);
/* clear everything except the class header as the object APIs /* clear everything except the class header as the object APIs
* will break otherwise */ * will break otherwise */
memset((char *) def + sizeof(def->parent), 0, memset((char *) def + sizeof(def->parent), 0,

View File

@ -415,6 +415,8 @@ struct _virStorageSource {
* registered with a full index (vda[3]) so that we can properly report just * registered with a full index (vda[3]) so that we can properly report just
* one event for it */ * one event for it */
bool thresholdEventWithIndex; bool thresholdEventWithIndex;
virStorageSourceFDTuple *fdtuple;
}; };
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref);

View File

@ -874,6 +874,7 @@ qemuDomainStorageSourcePrivateDispose(void *obj)
g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree); g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree);
g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree); g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree);
g_clear_pointer(&priv->tlsKeySecret, 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 int
qemuDomainPrepareStorageSourceBlockdevNodename(virDomainDiskDef *disk, qemuDomainPrepareStorageSourceBlockdevNodename(virDomainDiskDef *disk,
virStorageSource *src, virStorageSource *src,
@ -10861,6 +10917,9 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virDomainDiskDef *disk,
if (qemuDomainPrepareStorageSourceNFS(src) < 0) if (qemuDomainPrepareStorageSourceNFS(src) < 0)
return -1; return -1;
if (qemuDomainPrepareStorageSourceFDs(src, priv) < 0)
return -1;
return 0; 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: * qemuDomainStartupCleanup:
* *
@ -12222,5 +12303,10 @@ qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv)
void void
qemuDomainStartupCleanup(virDomainObj *vm) qemuDomainStartupCleanup(virDomainObj *vm)
{ {
size_t i;
qemuDomainSecretDestroy(vm); qemuDomainSecretDestroy(vm);
for (i = 0; i < vm->def->ndisks; i++)
qemuDomainCleanupStorageSourceFD(vm->def->disks[i]->src);
} }

View File

@ -305,6 +305,9 @@ struct _qemuDomainStorageSourcePrivate {
/* key for decrypting TLS certificate */ /* key for decrypting TLS certificate */
qemuDomainSecretInfo *tlsKeySecret; qemuDomainSecretInfo *tlsKeySecret;
/* file descriptors if user asks for FDs to be passed */
qemuFDPass *fdpass;
}; };
virObject *qemuDomainStorageSourcePrivateNew(void); virObject *qemuDomainStorageSourcePrivateNew(void);
@ -925,6 +928,8 @@ int qemuDomainSecretChardevPrepare(virQEMUDriverConfig *cfg,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_NONNULL(4); ATTRIBUTE_NONNULL(4);
void qemuDomainCleanupStorageSourceFD(virStorageSource *src);
void qemuDomainStartupCleanup(virDomainObj *vm); void qemuDomainStartupCleanup(virDomainObj *vm);
int qemuDomainSecretPrepare(virQEMUDriver *driver, int qemuDomainSecretPrepare(virQEMUDriver *driver,

View File

@ -1016,6 +1016,7 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriver *driver,
ignore_value(qemuHotplugRemoveManagedPR(vm, VIR_ASYNC_JOB_NONE)); ignore_value(qemuHotplugRemoveManagedPR(vm, VIR_ASYNC_JOB_NONE));
} }
qemuDomainSecretDiskDestroy(disk); qemuDomainSecretDiskDestroy(disk);
qemuDomainCleanupStorageSourceFD(disk->src);
return ret; return ret;
} }