From: Kevin Wolf <kwolf@redhat.com>
To: Emanuele Giuseppe Esposito <eesposit@redhat.com>
Cc: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>,
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
Subject: Re: [PATCH v7 10/18] jobs: rename static functions called with job_mutex held
Date: Fri, 24 Jun 2022 16:29:25 +0200 [thread overview]
Message-ID: <YrXKRWO7tQ9yvFKI@redhat.com> (raw)
In-Reply-To: <b420f70a-6e69-1913-5019-05a8118a49f5@redhat.com>
Am 23.06.2022 um 13:19 hat Emanuele Giuseppe Esposito geschrieben:
>
>
> Am 23/06/2022 um 13:10 schrieb Vladimir Sementsov-Ogievskiy:
> > On 6/23/22 12:08, Emanuele Giuseppe Esposito wrote:
> >>
> >>
> >> Am 22/06/2022 um 20:38 schrieb Vladimir Sementsov-Ogievskiy:
> >>> On 6/22/22 17:26, Emanuele Giuseppe Esposito wrote:
> >>>>
> >>>>
> >>>> Am 21/06/2022 um 19:26 schrieb Vladimir Sementsov-Ogievskiy:
> >>>>> On 6/16/22 16:18, Emanuele Giuseppe Esposito wrote:
> >>>>>> With the*nop* job_lock/unlock placed, rename the static
> >>>>>> functions that are always under job_mutex, adding "_locked" suffix.
> >>>>>>
> >>>>>> List of functions that get this suffix:
> >>>>>> job_txn_ref job_txn_del_job
> >>>>>> job_txn_apply job_state_transition
> >>>>>> job_should_pause job_event_cancelled
> >>>>>> job_event_completed job_event_pending
> >>>>>> job_event_ready job_event_idle
> >>>>>> job_do_yield job_timer_not_pending
> >>>>>> job_do_dismiss job_conclude
> >>>>>> job_update_rc job_commit
> >>>>>> job_abort job_clean
> >>>>>> job_finalize_single job_cancel_async
> >>>>>> job_completed_txn_abort job_prepare
> >>>>>> job_needs_finalize job_do_finalize
> >>>>>> job_transition_to_pending job_completed_txn_success
> >>>>>> job_completed job_cancel_err
> >>>>>> job_force_cancel_err
> >>>>>>
> >>>>>> Note that "locked" refers to the*nop* job_lock/unlock, and not
> >>>>>> real_job_lock/unlock.
> >>>>>>
> >>>>>> No functional change intended.
> >>>>>>
> >>>>>> Signed-off-by: Emanuele Giuseppe Esposito<eesposit@redhat.com>
> >>>>>
> >>>>>
> >>>>> Hmm. Maybe it was already discussed.. But for me it seems, that it
> >>>>> would
> >>>>> be simpler to review previous patches, that fix job_ API users to use
> >>>>> locking properly, if this renaming go earlier.
> >>>>>
> >>>>> Anyway, in this series, we can't update everything at once. So
> >>>>> patch to
> >>>>> patch, we make the code more and more correct. (yes I remember that
> >>>>> lock() is a noop, but I should review thinking that it real,
> >>>>> otherwise,
> >>>>> how to review?)
> >>>>>
> >>>>> So, I'm saying about formal correctness of using lock() unlock()
> >>>>> function in connection with introduced _locked prifixes and in
> >>>>> connection with how it should finally work.
> >>>>>
> >>>>> You do:
> >>>>>
> >>>>> 05. introduce some _locked functions, that just duplicates, and
> >>>>> job_pause_point_locked() is formally inconsistent, as I said.
> >>>>>
> >>>>> 06. Update a lot of places, to give them their final form (but not
> >>>>> final, as some functions will be renamed to _locked, some not, hard to
> >>>>> imagine)
> >>>>>
> >>>>> 07,08,09. Update some more, and even more places. very hard to track
> >>>>> formal correctness of using locks
> >>>>>
> >>>>> 10-...: rename APIs.
> >>>>>
> >>>>>
> >>>>> What do you think about the following:
> >>>>>
> >>>>> 1. Introduce noop lock, and some internal _locked() versions, and keep
> >>>>> formal consistency inside job.c, considering all public interfaces as
> >>>>> unlocked:
> >>>>>
> >>>>> at this point:
> >>>>> - everything correct inside job.c
> >>>>> - no public interfaces with _locked prefix
> >>>>> - all public interfaces take mutex internally
> >>>>> - no external user take mutex by hand
> >>>>>
> >>>>> We can rename all internal static functions at this step too.
> >>>>>
> >>>>> 2. Introduce some public _locked APIs, that we'll use in next patches
> >>>>>
> >>>>> 3. Now start fixing external users in several patches:
> >>>>> - protect by mutex direct use of job fields
> >>>>> - make wider locks and move to _locked APIs inside them where
> >>>>> needed
> >>>>>
> >>>>>
> >>>>> In this scenario, every updated unit becomes formally correct after
> >>>>> update, and after all steps everything is formally correct, and we can
> >>>>> move to turning-on the mutex.
> >>>>>
> >>>>
> >>>> I don't understand your logic also here, sorry :(
> >>>>
> >>>> I assume you want to keep patch 1-4, then the problem is assing
> >>>> job_lock
> >>>> and renaming functions in _locked.
> >>>> So I would say the problem is in patch 5-6-10-11-12-13. All the others
> >>>> should be self contained.
> >>>>
> >>>> I understand patch 5 is a little hard to follow.
> >>>>
> >>>> Now, I am not sure what you propose here but it seems that the end goal
> >>>> is to just have the same result, but with additional intermediate steps
> >>>> that are just "do this just because in the next patch will be useful".
> >>>> I think the problem is that we are going to miss the "why we need the
> >>>> lock" logic in the patches if we do so.
> >>>>
> >>>> The logic I tried to convey in this order is the following:
> >>>> - job.h: add _locked duplicates for job API functions called with and
> >>>> without job_mutex
> >>>> Just create duplicates of functions
> >>>>
> >>>> - jobs: protect jobs with job_lock/unlock
> >>>> QMP and monitor functions call APIs that assume lock is taken,
> >>>> drivers must take explicitly the lock
> >>>>
> >>>> - jobs: rename static functions called with job_mutex held
> >>>> - job.h: rename job API functions called with job_mutex held
> >>>> - block_job: rename block_job functions called with job_mutex held
> >>>> *given* that some functions are always under lock, transform
> >>>> them in _locked. Requires the job_lock/unlock patch
> >>>>
> >>>> - job.h: define unlocked functions
> >>>> Comments on the public functions that are not _locked
> >>>>
> >>>>
> >>>> @Kevin, since you also had some feedbacks on the patch ordering, do you
> >>>> agree with this ordering or you have some other ideas?
> >>>>
> >>>> Following your suggestion, we could move patches 10-11-12-13 before
> >>>> patch 6 "jobs: protect jobs with job_lock/unlock".
> >>>>
> >>>> (Apologies for changing my mind, but being the second complain I am
> >>>> starting to reconsider reordering the patches).
> >>>>
> >>>
> >>> In two words, what I mean: let's keep the following invariant from patch
> >>> to patch:
> >>>
> >>> 1. Function that has _locked() prefix is always called with lock held
> >>> 2. Function that has _locked() prefix never calls functions that take
> >>> lock by themselves so that would dead-lock
> >>> 3. Function that is documented as "called with lock not held" is never
> >>> called with lock held
> >>>
> >>> That what I mean by "formal correctness": yes, we know that lock is
> >>> noop, but still let's keep code logic to correspond function naming and
> >>> comments that we add.
> >>>
> >>
> >> Ok I get what you mean, but then we have useless changes for public
> >> functions that eventually will only be _locked() like job_next_locked:
> >>
> >> The function is always called in a loop, so it is pointless to take the
> >> lock inside. Therefore the patch would be "incorrect" on its own anyways.
> >>
> >> Then, we would have a patch where we add the lock guard inside, and
> >> another one where we remove it and rename to _locked and take the lock
> >> outside. Seems unnecessary to me.
> >
> > For me it looks a bit simpler than you describe. And anyway keeping the
> > correctness from patch to patch worth the complexity. I'll give an
> > argument.
> >
> > First what is the best practices? Best practices is when every patch is
> > good and absolutely correct. So that you can apply any number of patches
> > from the beginning of the series (01-NN), commit them to master and this
> > will break neither compilation, nor tests, nor readability, nothing.
> > This makes the review process iterable: if I'm OK with patches 01-03, I
> > give them r-b and don't think about them. I don't have to keep in mind
> > any tricky things. And I can review 04 several days later not rereading
> > 01-03 (or at least I can consider applied 01-03 as a good correct base
> > state). This way I'm sure, that if I reviewed all patches one-by-one,
> > each one is correct, then the whole thing is correct.
> >
> > A lot harder to review when we have only collective correctness: the
> > whole series being applied make a correct thing, but we can't say it
> > about intermediate states. In your series we can't be absolutely correct
> > with each patch, as we have to switch from aio-context lock to mutex in
> > one patch, that's why mutex is added as noop. That's a reasonable and
> > (seems) unsolvable drawback. That's a thing I have to keep in mind
> > during the whole review. But I'd prefer not add more such things, like
> > comments and _locked suffixes that don't correspond to the code.
> >
> > With the invariant that I propose, the following logic works:
> >
> > If
> > 1. we keep the invariant from patch to patch
> > AND
> > 2. at the end we have updated all users of the internal and external
> > APIs, not missed some file or function
> > Then everything is correct at the end.
> >
> > Without the invariant I can't prove that everything is correct at the
> > end, as it is hard to follow the degree of correctness from patch to
> > patch. In your way the only invariant that we have from patch to patch,
> > is that mutex is noop, so all changes do nothing, and therefore they are
> > correct. This way I can give an r-b to all such patches not thinking
> > about details, they are noop. But when I finally have to review the
> > patch that turns on the mutex, I'll have to recheck all internal and
> > external API users, which is equivalent to review all the changes merged
> > into one patch.
> >
> >
> >
> > Consider the case with job_next. The most correct way to update it IMHO:
> >
> > 1. Add lock inside job_next() and add job_next_locked() - in one patch
> > with other similar changes of job.c and job.h.
> >
> > At this moment we have job_next() calls in a loop, which is not good (we
> > want larger critical section), but that doesn't break the invariant I
> > proposed above.
>
> The only thing I am pointing here is that this breaks "readability",
> meaning if someone bisects here it will find a very weird situation
> (aside from the fact that there is a noop lock).
>
> But I guess this is fine, as long as I write it in the commit message.
>
> And since these patch are waiting here for more than 3 months now, I
> would say if the others (Kevin?) agree I will change the order with what
> you proposed here.
Yes, I think Vladimir is having the same difficulties with reading the
series as I had. And I believe his suggestion would make the
intermediate states less impossible to review. The question is how much
work it would be and whether you're willing to do this. As I said, if
reorganising is too hard, I'm okay with just ignoring the intermediate
state and reviewing the series as if it were a single patch.
Kevin
next prev parent reply other threads:[~2022-06-24 14:50 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-16 13:18 [PATCH v7 00/18] job: replace AioContext lock with job_mutex Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 01/18] job.c: make job_mutex and job_lock/unlock() public Emanuele Giuseppe Esposito
2022-06-21 13:47 ` Vladimir Sementsov-Ogievskiy
2022-06-24 18:22 ` Vladimir Sementsov-Ogievskiy
2022-06-28 13:08 ` Emanuele Giuseppe Esposito
2022-06-28 15:20 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 02/18] job.h: categorize fields in struct Job Emanuele Giuseppe Esposito
2022-06-21 14:29 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 03/18] job.c: API functions not used outside should be static Emanuele Giuseppe Esposito
2022-06-21 14:34 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 04/18] aio-wait.h: introduce AIO_WAIT_WHILE_UNLOCKED Emanuele Giuseppe Esposito
2022-06-21 14:40 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 05/18] job.h: add _locked duplicates for job API functions called with and without job_mutex Emanuele Giuseppe Esposito
2022-06-21 15:03 ` Vladimir Sementsov-Ogievskiy
2022-06-22 14:26 ` Emanuele Giuseppe Esposito
2022-06-22 18:12 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 06/18] jobs: protect jobs with job_lock/unlock Emanuele Giuseppe Esposito
2022-06-21 16:47 ` Vladimir Sementsov-Ogievskiy
2022-06-21 17:09 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 07/18] jobs: add job lock in find_* functions Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 08/18] jobs: use job locks also in the unit tests Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 09/18] block/mirror.c: use of job helpers in drivers to avoid TOC/TOU Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 10/18] jobs: rename static functions called with job_mutex held Emanuele Giuseppe Esposito
2022-06-21 17:26 ` Vladimir Sementsov-Ogievskiy
2022-06-22 14:26 ` Emanuele Giuseppe Esposito
2022-06-22 18:38 ` Vladimir Sementsov-Ogievskiy
2022-06-23 9:08 ` Emanuele Giuseppe Esposito
2022-06-23 11:10 ` Vladimir Sementsov-Ogievskiy
2022-06-23 11:19 ` Emanuele Giuseppe Esposito
2022-06-23 11:58 ` Vladimir Sementsov-Ogievskiy
2022-06-24 14:29 ` Kevin Wolf [this message]
2022-06-24 15:28 ` Paolo Bonzini
2022-06-24 17:20 ` Emanuele Giuseppe Esposito
2022-06-28 7:40 ` Emanuele Giuseppe Esposito
2022-06-28 10:47 ` Vladimir Sementsov-Ogievskiy
2022-06-28 13:04 ` Emanuele Giuseppe Esposito
2022-06-28 15:22 ` Vladimir Sementsov-Ogievskiy
2022-06-28 15:26 ` Vladimir Sementsov-Ogievskiy
2022-06-28 17:28 ` Emanuele Giuseppe Esposito
2022-06-28 19:42 ` Vladimir Sementsov-Ogievskiy
2022-06-16 13:18 ` [PATCH v7 11/18] job.h: rename job API " Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 12/18] block_job: rename block_job " Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 13/18] job.h: define unlocked functions Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 14/18] commit and mirror: create new nodes using bdrv_get_aio_context, and not the job aiocontext Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 15/18] job: detect change of aiocontext within job coroutine Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 16/18] jobs: protect job.aio_context with BQL and job_mutex Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 17/18] job.c: enable job lock/unlock and remove Aiocontext locks Emanuele Giuseppe Esposito
2022-06-16 13:18 ` [PATCH v7 18/18] block_job_query: remove atomic read Emanuele Giuseppe Esposito
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=YrXKRWO7tQ9yvFKI@redhat.com \
--to=kwolf@redhat.com \
--cc=armbru@redhat.com \
--cc=eesposit@redhat.com \
--cc=fam@euphon.net \
--cc=hreitz@redhat.com \
--cc=jsnow@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.