On 2018-12-14 12:26 p.m., Nicholas Kazlauskas wrote: > [Why] > The behavior of drm_atomic_helper_cleanup_planes differs depending on > whether the commit was asynchronous or not. When it's called from > amdgpu_dm_atomic_commit_tail during a typical atomic commit the > plane state has been swapped so it calls cleanup_fb on the old plane > state. > > However, in the asynchronous commit codepath the call to > drm_atomic_helper_commit also calls dm_plane_helper_cleanup_fb after > atomic_async_update has been called. Since the plane state is updated > in place and has not been swapped the cleanup_fb call affects the new > plane state. > > This results in a use after free for the given sequence: > > - Fast update, fb1 pin/ref, fb1 unpin/unref > - Fast update, fb2 pin/ref, fb2 unpin/unref > - Slow update, fb1 pin/ref, fb2 unpin/unref > - Fast update, fb2 pin/ref -> use after free. bug > > [How] > Disallow framebuffer changes in the fast path. Since this includes > a NULL framebuffer, this means that only framebuffers that have > been previously pin+ref at least once will be used, preventing a > use after free. > > This has a significant throughput reduction for cursor updates where > the framebuffer changes. For most desktop usage this isn't a problem, > but it does introduce performance regressions for two specific IGT > tests: > > - cursor-vs-flip-toggle > - cursor-vs-flip-varying-size > > Cc: Leo Li <sunpeng.li@xxxxxxx> > Cc: Harry Wentland <harry.wentland@xxxxxxx> > Cc: Michel Dänzer <michel@xxxxxxxxxxx> > Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx> Reviewed-by: Harry Wentland <harry.wentland@xxxxxxx> Harry > --- > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > index d01315965af0..dc1eb9ec2c38 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > @@ -3628,10 +3628,20 @@ static int dm_plane_atomic_check(struct drm_plane *plane, > static int dm_plane_atomic_async_check(struct drm_plane *plane, > struct drm_plane_state *new_plane_state) > { > + struct drm_plane_state *old_plane_state = > + drm_atomic_get_old_plane_state(new_plane_state->state, plane); > + > /* Only support async updates on cursor planes. */ > if (plane->type != DRM_PLANE_TYPE_CURSOR) > return -EINVAL; > > + /* > + * DRM calls prepare_fb and cleanup_fb on new_plane_state for > + * async commits so don't allow fb changes. > + */ > + if (old_plane_state->fb != new_plane_state->fb) > + return -EINVAL; > + > return 0; > } > > _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx