Re: [PATCH 54/60] drm/sun4i: layer: Convert to atomic_create_state

2026-07-09 Thread sashiko-bot
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) 
to consider:
- [Medium] Leftover state destruction code in `atomic_create_state` callback 
violates API contract
--

--- Patch [54]: [PATCH 54/60] drm/sun4i: layer: Convert to atomic_create_state 
---
commit 85f4174b6e45254800a7a99399fee4bf10972b0f
Author: Maxime Ripard 

drm/sun4i: layer: Convert to atomic_create_state

This commit converts the plane reset implementation in sun4i to use
atomic_create_state instead. The conversion relies on a Coccinelle semantic
patch to rename the functions and update the DRM plane function assignments.

> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c 
> b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index d65587d96d9ee..b165960ca8e5d 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -16,7 +16,7 @@
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> -static void sun4i_backend_layer_reset(struct drm_plane *plane)
> +static struct drm_plane_state *sun4i_backend_layer_create_state(struct 
> drm_plane *plane)
>  {
>   struct sun4i_layer_state *state;
>  
> @@ -30,8 +30,12 @@ static void sun4i_backend_layer_reset(struct drm_plane 
> *plane)
>   }

[Severity: Medium]
Does the Coccinelle script miss the plane state destruction block here?

Looking at sun4i_backend_layer_create_state() in sun4i_layer.c, the untouched
code right above this hunk still contains legacy state destruction logic:

if (plane->state) {
state = state_to_sun4i_layer_state(plane->state);
__drm_atomic_helper_plane_destroy_state(&state->state);
kfree(state);
plane->state = NULL;
}

Since atomic_create_state is expected to be a pure constructor without side
effects, shouldn't this block be removed?

While plane->state is currently guaranteed to be NULL when this is called by
the DRM core, retaining this block could lead to a use-after-free if any driver
logic later calls this hook directly on an active plane.

[ ... ]

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=54


[PATCH 54/60] drm/sun4i: layer: Convert to atomic_create_state

2026-07-09 Thread Maxime Ripard
The plane reset implementation creates a custom state
subclass, but only initializes a pristine state without resetting any
hardware. This is equivalent to what atomic_create_state expects.
Convert to it.

The conversion was done using the following Coccinelle semantic patch:

@@
identifier funcs;
symbol drm_atomic_helper_plane_reset;
symbol drm_atomic_helper_plane_create_state;
@@

struct drm_plane_funcs funcs = {
  ...,
- .reset = drm_atomic_helper_plane_reset,
+ .atomic_create_state = drm_atomic_helper_plane_create_state,
  ...,
};

@match_struct_reset@
identifier funcs, reset_func;
@@
struct drm_plane_funcs funcs = {
...,
.reset = reset_func,
...,
};

@reset_uses_helpers depends on match_struct_reset@
identifier match_struct_reset.reset_func;
@@

 void reset_func(...)
 {
<+...
(
__drm_atomic_helper_plane_reset(...);
|
__drm_gem_reset_shadow_plane(...);
)
...+>
 }

@match_struct_destroy@
identifier funcs, destroy_func;
@@
struct drm_plane_funcs funcs = {
...,
.atomic_destroy_state = destroy_func,
...,
};

@script:python renamed_func@
old_name << match_struct_reset.reset_func;
new_name;
@@
if old_name.endswith("_reset"):
coccinelle.new_name = old_name.replace("_reset", "_create_state")
else:
coccinelle.new_name = old_name

@update_struct depends on match_struct_reset && reset_uses_helpers@
identifier match_struct_reset.funcs, match_struct_reset.reset_func;
identifier renamed_func.new_name;
@@
struct drm_plane_funcs funcs = {
...,
-   .reset = reset_func,
+   .atomic_create_state = new_name,
...,
};

@drop_destroy depends on update_struct && match_struct_destroy@
identifier match_struct_reset.reset_func;
identifier match_struct_destroy.destroy_func;
identifier container_func;
identifier P;
symbol drm_atomic_helper_plane_destroy_state;
symbol __drm_atomic_helper_plane_destroy_state;
@@

 void reset_func(struct drm_plane *P)
 {
...
(
-   if (P->state) {
-   <+...
(
-   drm_atomic_helper_plane_destroy_state(P, P->state);
|
-   __drm_atomic_helper_plane_destroy_state(P->state);
|
-   P->funcs->atomic_destroy_state(P, P->state);
|
-   destroy_func(P, P->state);
)
-   ...+>
-   }
|
-   drm_WARN_ON_ONCE(P->dev, P->state);
|
-   WARN_ON(P->state);
)
...
(
-   kfree(P->state);
|
-   kfree(container_func(P->state));
|
// kfree is optional
)
(
-   P->state = NULL;
|
// plane->state clearing is optional
)
...
 }

@drop_destroy_mtk depends on update_struct@
identifier P;
symbol __drm_atomic_helper_plane_destroy_state;
symbol to_mtk_plane_state;
@@

 void mtk_plane_reset(struct drm_plane *P)
 {
...
-   if (P->state) {
-   __drm_atomic_helper_plane_destroy_state(P->state);
-   ...
-   } else {
...
-   }
...
 }

@transform_nv50_wndw depends on update_struct@
identifier S;
@@

 void nv50_wndw_reset(...)
 {
...
-   if (WARN_ON(!(S = kzalloc_obj(*S
+   S = kzalloc_obj(*S);
+   if (WARN_ON(!S))
return;
...
 }

@transform_kzalloc depends on update_struct@
identifier match_struct_reset.reset_func;
identifier P, S;
statement ST;
statement list STL;
@@

 void reset_func(struct drm_plane *P)
 {
<...
S = kzalloc_obj(*S);
(
-   if (S)
-   {
-   STL
-   }
+   if (!S) return;
+
+   STL
|
-   if (S) ST
+   if (!S) return;
+
+   ST
)
...>
 }

@transform_body depends on update_struct@
identifier match_struct_reset.reset_func;
identifier renamed_func.new_name;
identifier S, P;
expression PS;
@@
- void reset_func(struct drm_plane *P)
+ struct drm_plane_state *new_name(struct drm_plane *P)
{
...
S = kzalloc_obj(*S);
...
(
if (!S) {
...
-   return;
+   return ERR_PTR(-ENOMEM);
}
|
if (WARN_ON(!S)) {
...
-   return;
+   return ERR_PTR(-ENOMEM);
}
|
if (S == NULL) {
...
-   return;
+   return ERR_PTR(-ENOMEM);
}
)
...
(
-   __drm_atomic_helper_plane_reset(P, PS);
+   __drm_atomic_helper_plane_state_init(PS, P);
|
-   __drm_gem_reset_shadow_plane(P, PS);
+   __drm_gem_shadow_plane_state_init(P, PS);
)
...
}

@update_early_return depends on update_struct@
identifier match_struct_reset.reset_func;
identifier renamed_func.new_name;
identifier P;
expression PS;
@@
 struct drm_plane_state *new_name(struct drm_plane *P)
{
<+...
-   return;
+   return ERR_PTR(-EINVAL);
...+>
}

@update_return_plane depends on update_struct@
identifier match_struct_reset.reset_func;
identifier renamed_func.new_name;
identifier P;
expression PS;
@@
 struct drm_plane_state *new_name(struct drm_plane *P)
{
...