[libvirt] [PATCH] qemu: save config after pivot only if domain is persistent

Michael Chapman mike at very.puzzling.org
Tue Jan 5 00:38:07 UTC 2016


On Mon, 4 Jan 2016, Peter Krempa wrote:
> On Thu, Dec 31, 2015 at 16:42:52 +1100, Michael Chapman wrote:
>> When pivoting after a completed block job, only save the domain's
>> persistent configuration if the domain is actually marked persistent.
>>
>> This commit also refactors the logic surrounding the copying of the new
>> disk definition into vm->newDef to avoid a NULL pointer dereference if
>> virStorageSourceCopy were to fail to allocate memory.
>
> This commit is fixing two separate things in one commit, which is not
> really good practice. Please repost this as two patches.

No problem, I can do that.

>>
>> Signed-off-by: Michael Chapman <mike at very.puzzling.org>
>> ---
>>  src/qemu/qemu_blockjob.c | 34 ++++++++++++++--------------------
>>  1 file changed, 14 insertions(+), 20 deletions(-)
>>
>> diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
>> index 1d5b7ce..ae936a2 100644
>> --- a/src/qemu/qemu_blockjob.c
>> +++ b/src/qemu/qemu_blockjob.c
>> @@ -116,26 +116,20 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>>      switch ((virConnectDomainEventBlockJobStatus) status) {
>>      case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
>>          if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
>> -            if (vm->newDef) {
>> -                virStorageSourcePtr copy = NULL;
>> -
>> -                if ((persistDisk = virDomainDiskByName(vm->newDef,
>> -                                                       disk->dst, false))) {
>> -                    copy = virStorageSourceCopy(disk->mirror, false);
>> -                    if (virStorageSourceInitChainElement(copy,
>> -                                                         persistDisk->src,
>> -                                                         true) < 0) {
>> -                        VIR_WARN("Unable to update persistent definition "
>> -                                 "on vm %s after block job",
>> -                                 vm->def->name);
>> -                        virStorageSourceFree(copy);
>> -                        copy = NULL;
>> -                        persistDisk = NULL;
>> -                    }
>> -                }
>> -                if (copy) {
>> +            if (vm->newDef &&
>> +                (persistDisk = virDomainDiskByName(vm->newDef, disk->dst, false))) {
>> +                virStorageSourcePtr copy = virStorageSourceCopy(disk->mirror, false);
>> +                if (copy && virStorageSourceInitChainElement(copy,
>> +                                                             persistDisk->src,
>> +                                                             true) == 0) {a
>
> The new code will result in a line exceeding 80 cols. Since it's not
> very long, it's acceptable though.
>
>>                      virStorageSourceFree(persistDisk->src);
>>                      persistDisk->src = copy;
>> +                } else {
>> +                    VIR_WARN("Unable to update persistent definition "
>> +                             "on vm %s after block job",
>> +                             vm->def->name);
>> +                    virStorageSourceFree(copy);
>> +                    persistDisk = NULL;
>>                  }
>>              }
>>
>> @@ -188,8 +182,8 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
>>          if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
>>              VIR_WARN("Unable to save status on vm %s after block job",
>>                       vm->def->name);
>> -        if (persistDisk && virDomainSaveConfig(cfg->configDir,
>> -                                               vm->newDef) < 0)
>> +        if (vm->persistent && persistDisk &&
>
> I'm not quite sure how this would happen. If there isn't a persistent
> configuration, how did we get to having the persistDisk object?
>
> If this happened in some way, the problem then is that vm->newDef was
> not freed or is present in any way so we should fix the origin and not
> this symptom.

I spent a lot of time trying to work this out myself, and although I can 
see what the code is doing I don't really understand the rationale or 
history behind it all.

vm->newDef is supposed to be the "new domain definition to activate on 
shutdown", according to domain_conf.h. What's confusing though is that it 
is possible for this to exist even on transient domains.

qemuProcessInit calls virDomainObjSetDefTransient ("so any part of the 
startup process can add runtime state to vm->def that won't be 
persisted"), and virDomainObjSetDefTransient actually *sets* vm->newDef. 
If the domain is subsequently undefined, vm->persistent is set to 0 but 
vm->newDef is left alone.

So it's possible for vm->newDef to be non-NULL even though 
vm->persistent is 0.

I had initially thought about putting the vm->persistent test at the top 
of this code block, so persistDisk was never set if the domain was 
transient. However the problem with that approach is that it means 
vm->newDef never gets updated at the completion of the block job, yet it's 
still possible to get this "inactive" domain XML via virDomainGetXMLDesc.

I thought it would be simplest and safest to keep updating vm->newDef as 
before, but just not write out the config to disk if the domain wasn't 
actually persistent.

>> +            virDomainSaveConfig(cfg->configDir, vm->newDef) < 0)
>>              VIR_WARN("Unable to update persistent definition on vm %s "
>>                       "after block job", vm->def->name);
>>      }
>
> Peter

- Michael




More information about the libvir-list mailing list