All of lore.kernel.org
 help / color / mirror / Atom feed
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>
Cc: qemu-block@nongnu.org, Hanna Reitz <hreitz@redhat.com>,
	Paolo Bonzini <pbonzini@redhat.com>, John Snow <jsnow@redhat.com>,
	Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
	Wen Congyang <wencongyang2@huawei.com>,
	Xie Changlong <xiechanglong.d@gmail.com>,
	Markus Armbruster <armbru@redhat.com>,
	Stefan Hajnoczi <stefanha@redhat.com>, Fam Zheng <fam@euphon.net>,
	qemu-devel@nongnu.org,
	Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Subject: Re: [PATCH v10 13/21] job: detect change of aiocontext within job coroutine
Date: Tue, 16 Aug 2022 17:09:33 +0200	[thread overview]
Message-ID: <85f03feb-0502-b32d-9bdf-f3239d759c87@redhat.com> (raw)
In-Reply-To: <YuzWy1wQPf6HXl+0@redhat.com>



Am 05/08/2022 um 10:37 schrieb Kevin Wolf:
> Am 25.07.2022 um 09:38 hat Emanuele Giuseppe Esposito geschrieben:
>> From: Paolo Bonzini <pbonzini@redhat.com>
>>
>> We want to make sure access of job->aio_context is always done
>> under either BQL or job_mutex.
> 
> Is this the goal of this series? If so, it would have been useful to
> state somewhere more obvious, because I had assumed that holding the BQL
> would not be considered enough, but everyone needs to hold the job_mutex.

It is the goal for this patch :)
The whole job API can't rely on BQL since there are coroutines running
in another aiocontext.
> 
>> The problem is that using
>> aio_co_enter(job->aiocontext, job->co) in job_start and job_enter_cond
>> makes the coroutine immediately resume, so we can't hold the job lock.
>> And caching it is not safe either, as it might change.
>>
>> job_start is under BQL, so it can freely read job->aiocontext, but
>> job_enter_cond is not. In order to fix this, use aio_co_wake():
>> the advantage is that it won't use job->aiocontext, but the
>> main disadvantage is that it won't be able to detect a change of
>> job AioContext.
>>
>> Calling bdrv_try_set_aio_context() will issue the following calls
>> (simplified):
>> * in terms of  bdrv callbacks:
>>   .drained_begin -> .set_aio_context -> .drained_end
>> * in terms of child_job functions:
>>   child_job_drained_begin -> child_job_set_aio_context -> child_job_drained_end
>> * in terms of job functions:
>>   job_pause_locked -> job_set_aio_context -> job_resume_locked
>>
>> We can see that after setting the new aio_context, job_resume_locked
>> calls again job_enter_cond, which then invokes aio_co_wake(). But
>> while job->aiocontext has been set in job_set_aio_context,
>> job->co->ctx has not changed, so the coroutine would be entering in
>> the wrong aiocontext.
>>
>> Using aio_co_schedule in job_resume_locked() might seem as a valid
>> alternative, but the problem is that the bh resuming the coroutine
>> is not scheduled immediately, and if in the meanwhile another
>> bdrv_try_set_aio_context() is run (see test_propagate_mirror() in
>> test-block-iothread.c), we would have the first schedule in the
>> wrong aiocontext, and the second set of drains won't even manage
>> to schedule the coroutine, as job->busy would still be true from
>> the previous job_resume_locked().
>>
>> The solution is to stick with aio_co_wake(), but then detect every time
>> the coroutine resumes back from yielding if job->aio_context
>> has changed. If so, we can reschedule it to the new context.
> 
> Hm, but with this in place, what does aio_co_wake() actually buy us
> compared to aio_co_enter()?
> 
> I guess it's a bit simpler code because you don't have to explicitly
> specify the AioContext, but we're still going to enter the coroutine in
> the wrong AioContext occasionally and have to reschedule it, just like
> in the existing code (except that the rescheduling doesn't exist there
> yet).
> 
> So while I don't disagree with the change, I don't think the
> justification in the commit message is right for this part.

What do you suggest to change?

> 
>> Check for the aiocontext change in job_do_yield_locked because:
>> 1) aio_co_reschedule_self requires to be in the running coroutine
>> 2) since child_job_set_aio_context allows changing the aiocontext only
>>    while the job is paused, this is the exact place where the coroutine
>>    resumes, before running JobDriver's code.
>>
>> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
>> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>  job.c | 21 +++++++++++++++++++--
>>  1 file changed, 19 insertions(+), 2 deletions(-)
>>
>> diff --git a/job.c b/job.c
>> index b0729e2bb2..ecec66b44e 100644
>> --- a/job.c
>> +++ b/job.c
>> @@ -585,7 +585,9 @@ void job_enter_cond_locked(Job *job, bool(*fn)(Job *job))
>>      timer_del(&job->sleep_timer);
>>      job->busy = true;
>>      real_job_unlock();
>> -    aio_co_enter(job->aio_context, job->co);
>> +    job_unlock();
>> +    aio_co_wake(job->co);
>> +    job_lock();
> 
> The addition of job_unlock/lock is unrelated, this was necessary even
> before this patch.

Ok

> 
>>  }
>>  
>>  void job_enter_cond(Job *job, bool(*fn)(Job *job))
>> @@ -611,6 +613,8 @@ void job_enter(Job *job)
>>   */
>>  static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns)
>>  {
>> +    AioContext *next_aio_context;
>> +
>>      real_job_lock();
>>      if (ns != -1) {
>>          timer_mod(&job->sleep_timer, ns);
>> @@ -622,7 +626,20 @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns)
>>      qemu_coroutine_yield();
>>      job_lock();
>>  
>> -    /* Set by job_enter_cond() before re-entering the coroutine.  */
>> +    next_aio_context = job->aio_context;
>> +    /*
>> +     * Coroutine has resumed, but in the meanwhile the job AioContext
>> +     * might have changed via bdrv_try_set_aio_context(), so we need to move
>> +     * the coroutine too in the new aiocontext.
>> +     */
>> +    while (qemu_get_current_aio_context() != next_aio_context) {
>> +        job_unlock();
>> +        aio_co_reschedule_self(next_aio_context);
>> +        job_lock();
>> +        next_aio_context = job->aio_context;
>> +    }
>> +
>> +    /* Set by job_enter_cond_locked() before re-entering the coroutine.  */
>>      assert(job->busy);
>>  }
> 

Emanuele



  reply	other threads:[~2022-08-16 15:11 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-25  7:38 [PATCH v10 00/21] job: replace AioContext lock with job_mutex Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 01/21] job.c: make job_mutex and job_lock/unlock() public Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 02/21] job.h: categorize fields in struct Job Emanuele Giuseppe Esposito
2022-07-29 12:30   ` Kevin Wolf
2022-08-16 18:28   ` Stefan Hajnoczi
2022-07-25  7:38 ` [PATCH v10 03/21] job.c: API functions not used outside should be static Emanuele Giuseppe Esposito
2022-07-29 12:30   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 04/21] aio-wait.h: introduce AIO_WAIT_WHILE_UNLOCKED Emanuele Giuseppe Esposito
2022-07-29 12:33   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 05/21] job.c: add job_lock/unlock while keeping job.h intact Emanuele Giuseppe Esposito
2022-07-27 10:45   ` Vladimir Sementsov-Ogievskiy
2022-07-29 13:33   ` Kevin Wolf
2022-08-16 18:31   ` Stefan Hajnoczi
2022-07-25  7:38 ` [PATCH v10 06/21] job: move and update comments from blockjob.c Emanuele Giuseppe Esposito
2022-08-03 15:47   ` Kevin Wolf
2022-08-16 18:32   ` Stefan Hajnoczi
2022-07-25  7:38 ` [PATCH v10 07/21] blockjob: introduce block_job _locked() APIs Emanuele Giuseppe Esposito
2022-08-03 15:52   ` Kevin Wolf
2022-08-16 18:33   ` Stefan Hajnoczi
2022-07-25  7:38 ` [PATCH v10 08/21] jobs: add job lock in find_* functions Emanuele Giuseppe Esposito
2022-08-04 11:47   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 09/21] jobs: use job locks also in the unit tests Emanuele Giuseppe Esposito
2022-07-27 14:29   ` Vladimir Sementsov-Ogievskiy
2022-08-04 11:56   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 10/21] block/mirror.c: use of job helpers in drivers to avoid TOC/TOU Emanuele Giuseppe Esposito
2022-08-04 16:35   ` Kevin Wolf
2022-08-16 14:23     ` Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 11/21] jobs: group together API calls under the same job lock Emanuele Giuseppe Esposito
2022-07-27 14:50   ` Vladimir Sementsov-Ogievskiy
2022-08-04 17:10   ` Kevin Wolf
2022-08-16 14:54     ` Emanuele Giuseppe Esposito
2022-08-17  8:46       ` Kevin Wolf
2022-08-17  9:35         ` Emanuele Giuseppe Esposito
2022-08-17  9:59           ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 12/21] commit and mirror: create new nodes using bdrv_get_aio_context, and not the job aiocontext Emanuele Giuseppe Esposito
2022-08-05  8:14   ` Kevin Wolf
2022-08-16 14:57     ` Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 13/21] job: detect change of aiocontext within job coroutine Emanuele Giuseppe Esposito
2022-08-05  8:37   ` Kevin Wolf
2022-08-16 15:09     ` Emanuele Giuseppe Esposito [this message]
2022-08-17  8:34       ` Kevin Wolf
2022-08-17 11:16         ` Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 14/21] jobs: protect job.aio_context with BQL and job_mutex Emanuele Giuseppe Esposito
2022-07-27 15:22   ` Vladimir Sementsov-Ogievskiy
2022-08-05  9:12   ` Kevin Wolf
2022-08-17  8:04     ` Emanuele Giuseppe Esposito
2022-08-17 13:10       ` Emanuele Giuseppe Esposito
2022-08-18  8:48         ` Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 15/21] blockjob.h: categorize fields in struct BlockJob Emanuele Giuseppe Esposito
2022-08-05  9:21   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 16/21] blockjob: rename notifier callbacks as _locked Emanuele Giuseppe Esposito
2022-08-05  9:25   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 17/21] blockjob: protect iostatus field in BlockJob struct Emanuele Giuseppe Esposito
2022-07-27 15:29   ` Vladimir Sementsov-Ogievskiy
2022-08-16 12:39     ` Emanuele Giuseppe Esposito
2022-08-05 10:55   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 18/21] job.c: enable job lock/unlock and remove Aiocontext locks Emanuele Giuseppe Esposito
2022-07-27 15:53   ` Vladimir Sementsov-Ogievskiy
2022-08-16 12:52     ` Emanuele Giuseppe Esposito
2022-08-17 18:54       ` Vladimir Sementsov-Ogievskiy
2022-08-18  7:46         ` Emanuele Giuseppe Esposito
2022-08-19 15:49           ` Vladimir Sementsov-Ogievskiy
2022-08-16 12:53     ` Emanuele Giuseppe Esposito
2022-08-05 13:01   ` Kevin Wolf
2022-08-17 12:45     ` Emanuele Giuseppe Esposito
2022-07-25  7:38 ` [PATCH v10 19/21] block_job_query: remove atomic read Emanuele Giuseppe Esposito
2022-08-05 13:01   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 20/21] blockjob: remove unused functions Emanuele Giuseppe Esposito
2022-08-05 13:05   ` Kevin Wolf
2022-07-25  7:38 ` [PATCH v10 21/21] job: " Emanuele Giuseppe Esposito
2022-08-05 13:09   ` Kevin Wolf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=85f03feb-0502-b32d-9bdf-f3239d759c87@redhat.com \
    --to=eesposit@redhat.com \
    --cc=armbru@redhat.com \
    --cc=fam@euphon.net \
    --cc=hreitz@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=vsementsov@virtuozzo.com \
    --cc=vsementsov@yandex-team.ru \
    --cc=wencongyang2@huawei.com \
    --cc=xiechanglong.d@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.