On 12/14/2018 12:41 PM, Kazlauskas, Nicholas wrote: > On 12/14/18 12:34 PM, Grodzovsky, Andrey wrote: >> >> On 12/14/2018 12:26 PM, 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 >> Shouldn't you have use after free already at this point ? >> >> Andrey > This assumes there was 1 reference on the bo. You would be getting use > after free on every single update (be it fast or slow) if this wasn't > the case. Why would I get it on every single update if it's all balanced - first pin/ref then unpin/unref ? > > So in the case where there was 1 reference on fb2 it's actually freed at > the end of slow update since the ref count is now 0. Then the use after > free happens: I still don't understand where exactly the 1 reference on fb2 during slow update comes form if all i see before that is 'Fast update, fb2 pin/ref, fb2 unpin/unref' - can you clarify that ? Andrey > >>> - Fast update, fb2 pin/ref -> use after free. bug > ...here. > > You can see this exact sequence happening in Michel's log. > > Nicholas Kazlauskas > >>> [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> >>> --- >>> 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