[libvirt] [PATCH v2 10/12] qemu_hotplug: Hotplug of reservations
Michal Privoznik
mprivozn at redhat.com
Tue Mar 6 17:31:28 UTC 2018
On 03/02/2018 06:55 PM, John Ferlan wrote:
>
>
> On 02/21/2018 01:11 PM, Michal Privoznik wrote:
>> Surprisingly, nothing special is happening here. If we are the
>> first to use the managed helper then spawn it. If not, we're
>> almost done.
>
> But wasn't there a very special reason to start it between fork and
> exec?
No. If you are referring to previous patch, the very special reason
applies to calling qemuProcessSetupOnePRDaemonHook() which places the
qemu-pr-helper process (well, at this stage it's still just our own
fork) into the namespace of qemu process.
> Does that still hold true? That is why can we start the daemon
> after exec now, but we couldn't before in the previous patch?
>
> It feels quite "disjoint" to have the unplug in a subsequent patch too.
> Considering them both in one just seems "better", but it's not a deal
> breaker.
>
>>
>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>> ---
>> src/qemu/qemu_hotplug.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++
>> src/qemu/qemu_process.c | 38 +++++++++++++++++++++-----
>> src/qemu/qemu_process.h | 7 +++++
>> 3 files changed, 110 insertions(+), 7 deletions(-)
>>
>> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
>> index f28006e3c..2ebb68fbc 100644
>> --- a/src/qemu/qemu_hotplug.c
>> +++ b/src/qemu/qemu_hotplug.c
>> @@ -348,6 +348,58 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
>> }
>>
>>
>> +static int
>> +qemuBuildPRDefInfoProps(virDomainObjPtr vm,
>
> qemuBuild? Why not qemuDomainAdd?
Dunno. Other functions have the same prefix, e.g.
qemuBuildSecretInfoProps().
>
>> + virDomainDiskDefPtr disk,
>> + virJSONValuePtr *prmgrProps,
>> + const char **prAlias,
>> + const char **prPath)
>> +{
>> + qemuDomainObjPrivatePtr priv = vm->privateData;
>> + qemuDomainStorageSourcePrivatePtr srcPriv;
>> + virJSONValuePtr props = NULL;
>> + int ret = -1;
>> +
>> + srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
>
> ohh, umm, in qemuDomainAttachDiskGeneric there's a :
>
> srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
> if (srcPriv) {
> secinfo = srcPriv->secinfo;
> encinfo = srcPriv->encinfo;
> }
>
> Which makes light dawn that it "was" possible for srcPriv == NULL and
> the "thought" that the subsequent deref is going to fail rather
> spectacularly. See commit '8056721cb' (and a couple of others).
>
> Although it seems patch 4 and your change to qemuDomainPrepareDiskSource
> to call qemuDomainStorageSourcePrivateNew instead of having it called in
> qemuDomainSecretStorageSourcePrepare would seem to ensure that disk
> source privateData is always allocated now - meaning a number of other
> places where srcPriv is/was checked are no longer necessary.
Yes. There are such places.
>
> Maybe that one change needs to be "extracted" out to make things
> obvious. Not required, but just thinking and typing thoughts.
Okay, I can try that. Also try removing those unnecessary checks, but as
I was proven many times, touching this part of libvirt code always ends
bad with me.
>
>> +
>> + *prmgrProps = NULL;
>> +
>> + if (priv->prPid != (pid_t) -1 ||
>> + !srcPriv->prd ||
>> + !srcPriv->prd->alias)
>> + return 0;
>> +
>> + if (virJSONValueObjectCreate(&props,
>> + "s:path", srcPriv->prd->path,
>> + NULL) < 0)
>> + goto cleanup;
>> +> + if (qemuProcessSetupOnePRDaemon(vm, disk) < 0)
>> + goto cleanup;> +
>> + *prAlias = srcPriv->prd->alias;
>> + *prPath = srcPriv->prd->path;
>> + *prmgrProps = props;
>> + props = NULL;
>> + ret = 0;
>> + cleanup:
>> + virJSONValueFree(props);
>> + return ret;
>> +}
>> +
>> +
>> +static void
>> +qemuDestroyPRDefObject(virDomainObjPtr vm,
>
> qemuDestroy? Why not qemuDomainDel?
It's counterpart. qemuBuildPRDef.. qemuDestroyPRDef..
>
>> + const char *alias,
>> + const char *path)
>> +{
>> + if (!alias)
>> + return;
>
> BTW: This is where I'd expect to remove the object and then...
>
>> +
>> + qemuProcessKillPRDaemons(vm, path, false);
>
> Just unlink the path... See some thoughts below...
>
>> +}
>> +
>> +
>> /**
>> * qemuDomainAttachDiskGeneric:
>> *
>> @@ -365,12 +417,16 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
>> char *devstr = NULL;
>> char *drivestr = NULL;
>> char *drivealias = NULL;
>> + const char *prAlias = NULL;
>> + const char *prPath = NULL;
>> bool driveAdded = false;
>> bool secobjAdded = false;
>> bool encobjAdded = false;
>> + bool prmgrAdded = false;
>> virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
>> virJSONValuePtr secobjProps = NULL;
>> virJSONValuePtr encobjProps = NULL;
>> + virJSONValuePtr prmgrProps = NULL;
>> qemuDomainStorageSourcePrivatePtr srcPriv;
>> qemuDomainSecretInfoPtr secinfo = NULL;
>> qemuDomainSecretInfoPtr encinfo = NULL;
>> @@ -403,6 +459,9 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
>> disk->info.alias) < 0)
>> goto error;
>>
>> + if (qemuBuildPRDefInfoProps(vm, disk, &prmgrProps, &prAlias, &prPath) < 0)
>> + goto error;
>> +
>> if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
>> goto error;
>>
>> @@ -435,6 +494,15 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
>> encobjAdded = true;
>> }
>>
>> + if (prmgrProps) {
>> + rv = qemuMonitorAddObject(priv->mon, "pr-manager-helper", prAlias,
>> + prmgrProps);
>> + prmgrProps = NULL; /* qemuMonitorAddObject consumes */
>> + if (rv < 0)
>> + goto exit_monitor;
>> + prmgrAdded = true;
>> + }
>> +
>
> So for one of the managed modes (as noted much earlier) we could be
> creating a object with a duplicated alias - does that work? I thought
> id= has to be unique.
How come? The first thing that qemuBuildPRDefInfoProps() does is it
checks 'priv->prPid != (pid_t) -1'. The fact that this pid is not -1
means that there is a pr-helper process already running.
>
>> if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
>> goto exit_monitor;
>> driveAdded = true;
>> @@ -455,6 +523,7 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
>> cleanup:
>> virJSONValueFree(secobjProps);
>> virJSONValueFree(encobjProps);
>> + virJSONValueFree(prmgrProps);
>> qemuDomainSecretDiskDestroy(disk);
>> VIR_FREE(devstr);
>> VIR_FREE(drivestr);
>> @@ -472,6 +541,8 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
>> ignore_value(qemuMonitorDelObject(priv->mon, secinfo->s.aes.alias));
>> if (encobjAdded)
>> ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
>> + if (prmgrAdded)
>> + ignore_value(qemuMonitorDelObject(priv->mon, prAlias));
>> if (qemuDomainObjExitMonitor(driver, vm) < 0)
>> ret = -2;
>> virErrorRestore(&orig_err);
>> @@ -481,6 +552,7 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
>> error:
>> qemuDomainDelDiskSrcTLSObject(driver, vm, disk->src);
>> ignore_value(qemuHotplugPrepareDiskAccess(driver, vm, disk, NULL, true));
>> + qemuDestroyPRDefObject(vm, prAlias, prPath);
>
> oh, I see, you're mixing the way TLS object tear down occurred and how
> other objects happen. If you're going to mimic TLS, then change
> qemuBuildPRDefInfoProps to be something like qemuDomainAddPRDefObject
> which would do the EnterMonitorAsync, Props mgmt, AddObject, and
> ExitMonitor.
>
> That way qemuDestroyPRDefObject changes to qemuDomainDelPRDefObject
> which would handle the failure path.
>
> Then I believe you don't have to pass around prAlias and prPath since
> they'd be "obtainable".
Actually, I'm mimicing qemuBuildSecretInfoProps().
>
>> goto cleanup;
>> }
>>
>> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
>> index 33e0ad30c..3a914b6c6 100644
>> --- a/src/qemu/qemu_process.c
>> +++ b/src/qemu/qemu_process.c
>> @@ -2556,16 +2556,40 @@ qemuProcessResctrlCreate(virQEMUDriverPtr driver,
>> }
>>
>>
>
> This subsequent hunk feels like it could have gone in for the previous
> patch. Or at the very least some function that would unlink the socket
> path for each of the sockets in ndisks that were created. Then that
> single unlink API gets exposed.
Well, the only socket we can unlink is for the managed pr-helper.
Otherwise we might be unlinking a socket that is still active. And since
I need to use those static functions only in this patch I'm exposing
them here.
>
>> -static void
>> -qemuProcessKillPRDaemons(virDomainObjPtr vm)
>> +void
>> +qemuProcessKillPRDaemons(virDomainObjPtr vm,
>> + const char *socketPath,
>> + bool force)
>
> The only time force == true is when socketPath == NULL... and that's
> only in the shutdown path. When socketPath != NULL, force == false, and
> we're going to unplug the socket, right?
Yes.
>
> Perhaps this would be cleaner if only @socketPath was in play. If NULL,
> then walk the ndisks looking for paths that you'll unlink first before
> killing the daemon.
>
> I actually think having a separate unlink the socket would be just fine.
> Does it really matter if it's the "last" one to stop the helper daemon?
I think it does, because if we did not stop it I can see people
complaining immediately. We would be leaving a SUID process around for
longer than needed. Which increases the attack surface (the process has
a socket which is writable to UID:GID of the corresponding qemu process
and can do RAWIO operations).
Michal
More information about the libvir-list
mailing list