drm_atomic_private_obj_init() initializes the modeset lock and adds the
object to the privobj_list before calling atomic_create_state().

However, if atomic_create_state() fails, the function returns the error
directly without removing the object from the list or cleaning up the
lock. This leaves a dangling entry in privobj_list and a leaked lock.

Fix this by unwinding both operations in an error path.

Suggested-by: Laurent Pinchart <[email protected]>
Signed-off-by: Maxime Ripard <[email protected]>
---
 drivers/gpu/drm/drm_atomic.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 9bb761eda59f..9973becb75ae 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1027,25 +1027,34 @@ static void drm_atomic_plane_print_state(struct 
drm_printer *p,
 int drm_atomic_private_obj_init(struct drm_device *dev,
                                struct drm_private_obj *obj,
                                const struct drm_private_state_funcs *funcs)
 {
        struct drm_private_state *state;
+       int ret;
+
        memset(obj, 0, sizeof(*obj));
 
        drm_modeset_lock_init(&obj->lock);
 
        obj->dev = dev;
        obj->funcs = funcs;
        list_add_tail(&obj->head, &dev->mode_config.privobj_list);
 
        state = obj->funcs->atomic_create_state(obj);
-       if (IS_ERR(state))
-               return PTR_ERR(state);
+       if (IS_ERR(state)) {
+               ret = PTR_ERR(state);
+               goto err_list_del;
+       }
 
        obj->state = state;
 
        return 0;
+
+err_list_del:
+       list_del(&obj->head);
+       drm_modeset_lock_fini(&obj->lock);
+       return ret;
 }
 EXPORT_SYMBOL(drm_atomic_private_obj_init);
 
 /**
  * drm_atomic_private_obj_fini - finalize private object

-- 
2.55.0

Reply via email to