drm/v3d: Fix global performance monitor reference counting
In the SET_GLOBAL ioctl, v3d_perfmon_find() bumps the reference count on
the perfmon it returns, but v3d_perfmon_set_global_ioctl() and
v3d_perfmon_delete() fail to release that reference on several paths:
1. v3d_perfmon_set_global_ioctl() leaks the reference on its error
paths.
2. CLEAR_GLOBAL leaks both the find reference and the reference
previously stashed in v3d->global_perfmon by the SET_GLOBAL ioctl
that configured it.
3. Destroying a perfmon that is the current global perfmon leaks the
reference stashed by the SET_GLOBAL ioctl.
Release each of these references explicitly.
Cc: stable@vger.kernel.org
Fixes: c6eabbab35 ("drm/v3d: Add DRM_IOCTL_V3D_PERFMON_SET_GLOBAL")
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Link: https://patch.msgid.link/20260531-v3d-perfmon-lifetime-v2-1-60ed4485a203@igalia.com
Signed-off-by: Maíra Canal <mcanal@igalia.com>
master
parent
30252e6f71
commit
6bf7e2affc
|
|
@ -309,8 +309,11 @@ static void v3d_perfmon_delete(struct v3d_file_priv *v3d_priv,
|
|||
if (perfmon == v3d->active_perfmon)
|
||||
v3d_perfmon_stop(v3d, perfmon, false);
|
||||
|
||||
/* If the global perfmon is being destroyed, set it to NULL */
|
||||
cmpxchg(&v3d->global_perfmon, perfmon, NULL);
|
||||
/* If the global perfmon is being destroyed, clean it and release
|
||||
* the reference stashed in v3d_perfmon_set_global_ioctl().
|
||||
*/
|
||||
if (cmpxchg(&v3d->global_perfmon, perfmon, NULL) == perfmon)
|
||||
v3d_perfmon_put(perfmon);
|
||||
|
||||
v3d_perfmon_put(perfmon);
|
||||
}
|
||||
|
|
@ -461,16 +464,27 @@ int v3d_perfmon_set_global_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
/* If the request is to clear the global performance monitor */
|
||||
if (req->flags & DRM_V3D_PERFMON_CLEAR_GLOBAL) {
|
||||
if (!v3d->global_perfmon)
|
||||
struct v3d_perfmon *old;
|
||||
|
||||
/* DRM_V3D_PERFMON_CLEAR_GLOBAL doesn't check if
|
||||
* v3d->global_perfmon == perfmon. Therefore, there
|
||||
* is no need to keep perfmon's reference.
|
||||
*/
|
||||
v3d_perfmon_put(perfmon);
|
||||
|
||||
old = xchg(&v3d->global_perfmon, NULL);
|
||||
if (!old)
|
||||
return -EINVAL;
|
||||
|
||||
xchg(&v3d->global_perfmon, NULL);
|
||||
v3d_perfmon_put(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmpxchg(&v3d->global_perfmon, NULL, perfmon))
|
||||
if (cmpxchg(&v3d->global_perfmon, NULL, perfmon)) {
|
||||
v3d_perfmon_put(perfmon);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue