[PATCH] qemu: blockjob: Transition into 'ready' state only from expected states

Michal Privoznik mprivozn at redhat.com
Wed Apr 21 10:17:16 UTC 2021


On 4/20/21 1:44 PM, Peter Krempa wrote:
> In certain rare occasions qemu can transition a block job which was
> already 'ready' into 'standby' and then back. If this happens in the
> following order libvirt will get confused about the actual job state:
> 
> 1) the block copy job is 'ready' (job->state == QEMU_BLOCKJOB_STATE_READY)
> 
> 2) user calls qemuDomainBlockJobAbort with VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT
>     flag but without VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC
> 
> 3) the block job is switched to synchronous event handling
> 
> 4) the block job blips to 'standby' and back to 'ready', the event is
>     not processed since the blockjob is in sync mode for now
> 
> 5) qemuDomainBlockJobPivot is called:
>      5.1) 'job-complete' QMP command is issued
>      5.2) job->state is set to QEMU_BLOCKJOB_STATE_PIVOTING
> 
> 6) code for synchronous-wait for the job completion in qemuDomainBlockJobAbort
>     is invoked
> 
> 7) the waiting loop calls qemuBlockJobUpdate:
> 
>      7.1) job->newstate is QEMU_BLOCKJOB_STATE_READY due to 4)
>      7.2) qemuBlockJobEventProcess is called
>      7.3) the handler for QEMU_BLOCKJOB_STATE_READY overwrites
>           job->state from QEMU_BLOCKJOB_STATE_PIVOTING to QEMU_BLOCKJOB_STATE_READY
> 
> 8) qemuDomainBlockJobAbort is looking for a finished job, so waits again
> 
> 9) qemu finishes the blockjob and transitions it into 'concluded' state
> 
> 10) qemuBlockJobUpdate is triggered again, this time finalizing the job.
>      10.1) job->newstate is = QEMU_BLOCKJOB_STATE_CONCLUDED
>            job->state is = QEMU_BLOCKJOB_STATE_READY
>      10.2) qemuBlockJobEventProcessConcluded is called, the function
>            checks whether there was an error with the blockjob. Since
>            there was no error job->newstate becomes
>            QEMU_BLOCKJOB_STATE_COMPLETED.
>      10.3) qemuBlockJobEventProcessConcludedTransition selects the action
>            for the appropriate block job type where we have:
> 
>      case QEMU_BLOCKJOB_TYPE_COPY:
>          if (job->state == QEMU_BLOCKJOB_STATE_PIVOTING && success)
>              qemuBlockJobProcessEventConcludedCopyPivot(driver, vm, job, asyncJob);
>          else
>              qemuBlockJobProcessEventConcludedCopyAbort(driver, vm, job, asyncJob);
>          break;
> 
>            Since job->state is QEMU_BLOCKJOB_STATE_READY,
>            qemuBlockJobProcessEventConcludedCopyAbort is called.
> 
> This patch forbids transitions to QEMU_BLOCKJOB_STATE_READY if the
> previous job state isn't QEMU_BLOCKJOB_STATE_RUNNING or
> QEMU_BLOCKJOB_STATE_NEW.
> 
> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1951507
> Signed-off-by: Peter Krempa <pkrempa at redhat.com>
> ---
>   src/qemu/qemu_blockjob.c | 19 +++++++++++++------
>   1 file changed, 13 insertions(+), 6 deletions(-)

Reviewed-by: Michal Privoznik <mprivozn at redhat.com>

Michal




More information about the libvir-list mailing list