qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 09/10] blockjob: reorganize block_job_completed_


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH 09/10] blockjob: reorganize block_job_completed_txn_abort
Date: Sat, 8 Apr 2017 18:03:02 +0800
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0


On 08/04/2017 09:15, John Snow wrote:
> 
> 
> On 03/23/2017 01:39 PM, Paolo Bonzini wrote:
>> This splits the part that touches job states from the part that invokes
>> callbacks.  It will be a bit simpler to understand once job states will
>> be protected by a different mutex than the AioContext lock.
>>
> 
> Maybe easier to review then, too :)

The idea is that the "touching job states" part (block_job_cancel_async)
doesn't release the mutex, while the "invokes callbacks" functions
(block_job_finish_sync, block_job_completed_single) part does.  It is
much simpler to understand if all block_job_cancel_asyncs are done first.

I should once more split code movement from changes, but I think this
patch is still reviewable on its own.  All the "introduce block job
mutex" does in block_job_completed_txn_abort is remove all
aio_context_acquire and release calls.

Paolo

>> Signed-off-by: Paolo Bonzini <address@hidden>
>> ---
>>  blockjob.c | 165 
>> ++++++++++++++++++++++++++++++++-----------------------------
>>  1 file changed, 88 insertions(+), 77 deletions(-)
>>
>> diff --git a/blockjob.c b/blockjob.c
>> index 093962b..3fa2885 100644
>> --- a/blockjob.c
>> +++ b/blockjob.c
>> @@ -76,6 +76,39 @@ BlockJob *block_job_get(const char *id)
>>      return NULL;
>>  }
>>  
>> +BlockJobTxn *block_job_txn_new(void)
>> +{
>> +    BlockJobTxn *txn = g_new0(BlockJobTxn, 1);
>> +    QLIST_INIT(&txn->jobs);
>> +    txn->refcnt = 1;
>> +    return txn;
>> +}
>> +
>> +static void block_job_txn_ref(BlockJobTxn *txn)
>> +{
>> +    txn->refcnt++;
>> +}
>> +
>> +void block_job_txn_unref(BlockJobTxn *txn)
>> +{
>> +    if (txn && --txn->refcnt == 0) {
>> +        g_free(txn);
>> +    }
>> +}
>> +
>> +void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job)
>> +{
>> +    if (!txn) {
>> +        return;
>> +    }
>> +
>> +    assert(!job->txn);
>> +    job->txn = txn;
>> +
>> +    QLIST_INSERT_HEAD(&txn->jobs, job, txn_list);
>> +    block_job_txn_ref(txn);
>> +}
>> +
>>  static void block_job_pause(BlockJob *job)
>>  {
>>      job->pause_count++;
>> @@ -336,6 +369,8 @@ void block_job_start(BlockJob *job)
>>  
>>  static void block_job_completed_single(BlockJob *job)
>>  {
>> +    assert(job->completed);
>> +
>>      if (!job->ret) {
>>          if (job->driver->commit) {
>>              job->driver->commit(job);
>> @@ -376,14 +411,49 @@ static void block_job_completed_single(BlockJob *job)
>>  static void block_job_cancel_async(BlockJob *job)
>>  {
>>      job->cancelled = true;
>> -    block_job_iostatus_reset(job);
>> +    if (!job->completed) {
>> +        block_job_iostatus_reset(job);
>> +    }
>> +}
>> +
>> +static int block_job_finish_sync(BlockJob *job,
>> +                                 void (*finish)(BlockJob *, Error **errp),
>> +                                 Error **errp)
>> +{
>> +    Error *local_err = NULL;
>> +    int ret;
>> +
>> +    assert(blk_bs(job->blk)->job == job);
>> +
>> +    block_job_ref(job);
>> +
>> +    if (finish) {
>> +        finish(job, &local_err);
>> +    }
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        block_job_unref(job);
>> +        return -EBUSY;
>> +    }
>> +    /* block_job_drain calls block_job_enter, and it should be enough to
>> +     * induce progress until the job completes or moves to the main thread.
>> +    */
>> +    while (!job->deferred_to_main_loop && !job->completed) {
>> +        block_job_drain(job);
>> +    }
>> +    while (!job->completed) {
>> +        aio_poll(qemu_get_aio_context(), true);
>> +    }
>> +    ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret;
>> +    block_job_unref(job);
>> +    return ret;
>>  }
>>  
>>  static void block_job_completed_txn_abort(BlockJob *job)
>>  {
>>      AioContext *ctx;
>>      BlockJobTxn *txn = job->txn;
>> -    BlockJob *other_job, *next;
>> +    BlockJob *other_job;
>>  
>>      if (txn->aborting) {
>>          /*
>> @@ -392,29 +462,34 @@ static void block_job_completed_txn_abort(BlockJob 
>> *job)
>>          return;
>>      }
>>      txn->aborting = true;
>> +    block_job_txn_ref(txn);
>> +
>>      /* We are the first failed job. Cancel other jobs. */
>>      QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
>>          ctx = blk_get_aio_context(other_job->blk);
>>          aio_context_acquire(ctx);
>>      }
>> +
>> +    /* Other jobs are "effectively" cancelled by us, set the status for
>> +     * them; this job, however, may or may not be cancelled, depending
>> +     * on the caller, so leave it. */
>>      QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
>> -        if (other_job == job || other_job->completed) {
>> -            /* Other jobs are "effectively" cancelled by us, set the status 
>> for
>> -             * them; this job, however, may or may not be cancelled, 
>> depending
>> -             * on the caller, so leave it. */
>> -            if (other_job != job) {
>> -                block_job_cancel_async(other_job);
>> -            }
>> -            continue;
>> +        if (other_job != job) {
>> +            block_job_cancel_async(other_job);
>>          }
>> -        block_job_cancel_sync(other_job);
>> -        assert(other_job->completed);
>>      }
>> -    QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
>> +    while (!QLIST_EMPTY(&txn->jobs)) {
>> +        other_job = QLIST_FIRST(&txn->jobs);
>>          ctx = blk_get_aio_context(other_job->blk);
>> +        if (!other_job->completed) {
>> +            assert(other_job->cancelled);
>> +            block_job_finish_sync(other_job, NULL, NULL);
>> +        }
>>          block_job_completed_single(other_job);
>>          aio_context_release(ctx);
>>      }
>> +
>> +    block_job_txn_unref(txn);
>>  }
>>  
>>  static void block_job_completed_txn_success(BlockJob *job)
>> @@ -502,37 +577,6 @@ void block_job_cancel(BlockJob *job)
>>      }
>>  }
>>  
>> -static int block_job_finish_sync(BlockJob *job,
>> -                                 void (*finish)(BlockJob *, Error **errp),
>> -                                 Error **errp)
>> -{
>> -    Error *local_err = NULL;
>> -    int ret;
>> -
>> -    assert(blk_bs(job->blk)->job == job);
>> -
>> -    block_job_ref(job);
>> -
>> -    finish(job, &local_err);
>> -    if (local_err) {
>> -        error_propagate(errp, local_err);
>> -        block_job_unref(job);
>> -        return -EBUSY;
>> -    }
>> -    /* block_job_drain calls block_job_enter, and it should be enough to
>> -     * induce progress until the job completes or moves to the main thread.
>> -    */
>> -    while (!job->deferred_to_main_loop && !job->completed) {
>> -        block_job_drain(job);
>> -    }
>> -    while (!job->completed) {
>> -        aio_poll(qemu_get_aio_context(), true);
>> -    }
>> -    ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret;
>> -    block_job_unref(job);
>> -    return ret;
>> -}
>> -
>>  /* A wrapper around block_job_cancel() taking an Error ** parameter so it 
>> may be
>>   * used with block_job_finish_sync() without the need for (rather nasty)
>>   * function pointer casts there. */
>> @@ -856,36 +900,3 @@ void block_job_defer_to_main_loop(BlockJob *job,
>>      aio_bh_schedule_oneshot(qemu_get_aio_context(),
>>                              block_job_defer_to_main_loop_bh, data);
>>  }
>> -
>> -BlockJobTxn *block_job_txn_new(void)
>> -{
>> -    BlockJobTxn *txn = g_new0(BlockJobTxn, 1);
>> -    QLIST_INIT(&txn->jobs);
>> -    txn->refcnt = 1;
>> -    return txn;
>> -}
>> -
>> -static void block_job_txn_ref(BlockJobTxn *txn)
>> -{
>> -    txn->refcnt++;
>> -}
>> -
>> -void block_job_txn_unref(BlockJobTxn *txn)
>> -{
>> -    if (txn && --txn->refcnt == 0) {
>> -        g_free(txn);
>> -    }
>> -}
>> -
>> -void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job)
>> -{
>> -    if (!txn) {
>> -        return;
>> -    }
>> -
>> -    assert(!job->txn);
>> -    job->txn = txn;
>> -
>> -    QLIST_INSERT_HEAD(&txn->jobs, job, txn_list);
>> -    block_job_txn_ref(txn);
>> -}
>>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]