From: Haneen Mohammed <hamohammed.sa@gmail.com>
To: Daniel Vetter <daniel@ffwll.ch>
Cc: seanpaul@chromium.org, rodrigosiqueiramelo@gmail.com,
dri-devel@lists.freedesktop.org
Subject: Re: [PATCH] drm/vkms: Fix race condition around accessing frame number
Date: Sat, 1 Sep 2018 20:53:52 +0300 [thread overview]
Message-ID: <20180901175352.GA14348@haneenDRM> (raw)
In-Reply-To: <20180831084140.GO21634@phenom.ffwll.local>
On Fri, Aug 31, 2018 at 10:41:40AM +0200, Daniel Vetter wrote:
> On Fri, Aug 24, 2018 at 02:16:34AM +0300, Haneen Mohammed wrote:
> > crtc_state is accessed by both vblank_handle() and the ordered
> > work_struct handle vkms_crc_work_handle() to retrieve and or update
> > the frame number for computed CRC.
> >
> > Since work_struct can fail, add frame_end to account for missing frame
> > numbers.
> >
> > use atomic_t witth appropriate flags for synchronization between hrtimer
> > callback and ordered work_struct handle since spinlock can't be used
> > with work_struct handle and mutex can't be used with hrtimer callback.
> >
> > This patch passes the following subtests from igt kms_pipe_crc_basic test:
> > bad-source, read-crc-pipe-A, read-crc-pipe-A-frame-sequence,
> > nonblocking-crc-pipe-A, nonblocking-crc-pipe-A-frame-sequence
> >
> > Signed-off-by: Haneen Mohammed <hamohammed.sa@gmail.com>
>
> So atomic_t is probably the greatest trap in the linux kernel. It sounds
> like the right thing, but in 99% of all case you want to use it it isn't.
> The trouble is that atomic_t is _very_ unordered, the only thing it
> guarantees is that atomic_t transactions to the _same_ variable are
> consistent. But anything else can be reordered at will.
>
> This is very confusing since the new C++ atomic standards has fully
> ordered atomics as the default, and you expressedly need to ask for the
> weakly ordered ones. In linux you need to sprinkle epic amounts of
> smb_barrier* and similar things around them to make atomic_t behave like a
> "normal" C++ atomic type.
>
> tldr; atomic_t is good for special refcounting needs, when the normal
> refcount_t doesn't cut it. Not much else.
>
> What usually should be done:
> - Use normal u64 (to match the vblank counter size) instead of atomic_t
> here.
> - Make sure all access is protect by an appropriate spinlock.
>
I see, thanks for the explanation!
hm would the patch be fine if I just switch atomic_t to u64 without
using spinlock? since that won't be possible with the work_struct.
Thanks,
Haneen
> > ---
> > drivers/gpu/drm/vkms/vkms_crc.c | 33 ++++++++++++++++++++++++++++++--
> > drivers/gpu/drm/vkms/vkms_crtc.c | 13 +++++++++++--
> > drivers/gpu/drm/vkms/vkms_drv.h | 6 ++++--
> > 3 files changed, 46 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_crc.c
> > index ed47d67cecd6..4a1ba5b7886a 100644
> > --- a/drivers/gpu/drm/vkms/vkms_crc.c
> > +++ b/drivers/gpu/drm/vkms/vkms_crc.c
> > @@ -34,6 +34,15 @@ static uint32_t _vkms_get_crc(struct vkms_crc_data *crc_data)
> > return crc;
> > }
> >
> > +/**
> > + * vkms_crc_work_handle - ordered work_struct to compute CRC
> > + *
> > + * @work: work_struct
> > + *
> > + * Work handler for computing CRCs. work_struct scheduled in
> > + * an ordered workqueue that's periodically scheduled to run by
> > + * _vblank_handle() and flushed at vkms_atomic_crtc_destroy_state().
> > + */
> > void vkms_crc_work_handle(struct work_struct *work)
> > {
> > struct vkms_crtc_state *crtc_state = container_of(work,
> > @@ -45,8 +54,18 @@ void vkms_crc_work_handle(struct work_struct *work)
> > output);
> > struct vkms_crc_data *primary_crc = NULL;
> > struct drm_plane *plane;
> > -
> > u32 crc32 = 0;
> > + u32 frame_start, frame_end;
> > +
> > + frame_start = atomic_read(&crtc_state->frame_start);
> > + frame_end = atomic_read(&crtc_state->frame_end);
> > + /* _vblank_handle() hasn't updated frame_start yet */
> > + if (!frame_start) {
>
> I think if we go with u64 we can ignore the issues for wrap-arround, since
> that will simply never happen. But a comment would be good.
>
> Aside from the atomic_t issue I think this looks good.
> -Daniel
>
> > + return;
> > + } else if (frame_start == frame_end) {
> > + atomic_set(&crtc_state->frame_start, 0);
> > + return;
> > + }
> >
> > drm_for_each_plane(plane, &vdev->drm) {
> > struct vkms_plane_state *vplane_state;
> > @@ -67,7 +86,17 @@ void vkms_crc_work_handle(struct work_struct *work)
> > if (primary_crc)
> > crc32 = _vkms_get_crc(primary_crc);
> >
> > - drm_crtc_add_crc_entry(crtc, true, crtc_state->n_frame, &crc32);
> > + frame_end = drm_crtc_accurate_vblank_count(crtc);
> > +
> > + /* queue_work can fail to schedule crc_work; add crc for
> > + * missing frames
> > + */
> > + while (frame_start <= frame_end)
> > + drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32);
> > +
> > + /* to avoid using the same value again */
> > + atomic_set(&crtc_state->frame_end, frame_end);
> > + atomic_set(&crtc_state->frame_start, 0);
> > }
> >
> > static int vkms_crc_parse_source(const char *src_name, bool *enabled)
> > diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
> > index 9d0b1a325a78..a170677acd46 100644
> > --- a/drivers/gpu/drm/vkms/vkms_crtc.c
> > +++ b/drivers/gpu/drm/vkms/vkms_crtc.c
> > @@ -22,8 +22,17 @@ static void _vblank_handle(struct vkms_output *output)
> > DRM_ERROR("vkms failure on handling vblank");
> >
> > if (state && output->crc_enabled) {
> > - state->n_frame = drm_crtc_accurate_vblank_count(crtc);
> > - queue_work(output->crc_workq, &state->crc_work);
> > + u32 frame = drm_crtc_accurate_vblank_count(crtc);
> > +
> > + /* update frame_start only if a queued vkms_crc_work_handle has
> > + * read the data
> > + */
> > + if (!atomic_read(&state->frame_start))
> > + atomic_set(&state->frame_start, frame);
> > +
> > + ret = queue_work(output->crc_workq, &state->crc_work);
> > + if (!ret)
> > + DRM_WARN("failed to queue vkms_crc_work_handle");
> > }
> >
> > spin_unlock(&output->lock);
> > diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> > index 2017a2ccc43d..4a3956a0549e 100644
> > --- a/drivers/gpu/drm/vkms/vkms_drv.h
> > +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> > @@ -39,12 +39,14 @@ struct vkms_plane_state {
> > * vkms_crtc_state - Driver specific CRTC state
> > * @base: base CRTC state
> > * @crc_work: work struct to compute and add CRC entries
> > - * @n_frame: frame number for computed CRC
> > + * @n_frame_start: start frame number for computed CRC
> > + * @n_frame_end: end frame number for computed CRC
> > */
> > struct vkms_crtc_state {
> > struct drm_crtc_state base;
> > struct work_struct crc_work;
> > - unsigned int n_frame;
> > + atomic_t frame_start;
> > + atomic_t frame_end;
> > };
> >
> > struct vkms_output {
> > --
> > 2.17.1
> >
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2018-09-01 17:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-23 23:16 [PATCH] drm/vkms: Fix race condition around accessing frame number Haneen Mohammed
2018-08-31 8:41 ` Daniel Vetter
2018-09-01 17:53 ` Haneen Mohammed [this message]
2018-09-03 7:29 ` Daniel Vetter
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=20180901175352.GA14348@haneenDRM \
--to=hamohammed.sa@gmail.com \
--cc=daniel@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=rodrigosiqueiramelo@gmail.com \
--cc=seanpaul@chromium.org \
/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.