panfrost: Fix Panfrost BO leak in error handling path

When panfrost_resource_init_afbc_headers() fails, freeing the newly
created resource is not enough, because we need to unreference its BOs.
This will also take care of freeing its resource label.

Also replace instances of FREE() in error-handling paths with
panfrost_resource_destroy(), as it is capable of handling partially
initialised resources.

Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Fixes: e3f2bc7963 ("panfrost: handle mmap failures")
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34224>
(cherry picked from commit 32b128be01)
This commit is contained in:
Adrián Larumbe 2025-06-13 01:39:29 +01:00 committed by Eric Engestrom
parent c76a7410dc
commit e1f6a0c4df
2 changed files with 32 additions and 32 deletions

View file

@ -4764,7 +4764,7 @@
"description": "panfrost: Fix Panfrost BO leak in error handling path",
"nominated": true,
"nomination_type": 2,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": "e3f2bc7963748096f7b4018cffe058a73081a760",
"notes": null

View file

@ -101,6 +101,31 @@ panfrost_clear_render_target(struct pipe_context *pipe,
height);
}
static void
panfrost_resource_destroy(struct pipe_screen *screen, struct pipe_resource *pt)
{
MESA_TRACE_FUNC();
struct panfrost_device *dev = pan_device(screen);
struct panfrost_resource *rsrc = (struct panfrost_resource *)pt;
if (rsrc->scanout)
renderonly_scanout_destroy(rsrc->scanout, dev->ro);
if (rsrc->shadow_image)
pipe_resource_reference(
(struct pipe_resource **)&rsrc->shadow_image, NULL);
if (rsrc->bo)
panfrost_bo_unreference(rsrc->bo);
free(rsrc->index_cache);
free(rsrc->damage.tile_map.data);
util_range_destroy(&rsrc->valid_buffer_range);
free(rsrc);
}
static struct pipe_resource *
panfrost_resource_from_handle(struct pipe_screen *pscreen,
const struct pipe_resource *templat,
@ -150,7 +175,7 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
pan_image_layout_init(dev->arch, &rsc->image.layout, &explicit_layout);
if (!valid) {
FREE(rsc);
panfrost_resource_destroy(pscreen, &rsc->base);
return NULL;
}
@ -159,7 +184,7 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
* memory space to mmap it etc.
*/
if (!rsc->bo) {
FREE(rsc);
panfrost_resource_destroy(pscreen, &rsc->base);
return NULL;
}
@ -830,7 +855,7 @@ panfrost_resource_create_with_modifier(struct pipe_screen *screen,
if (!so->scanout) {
mesa_loge("Failed to create scanout resource\n");
FREE(so);
panfrost_resource_destroy(screen, &so->base);
return NULL;
}
assert(handle.type == WINSYS_HANDLE_TYPE_FD);
@ -838,7 +863,7 @@ panfrost_resource_create_with_modifier(struct pipe_screen *screen,
close(handle.handle);
if (!so->bo) {
FREE(so);
panfrost_resource_destroy(screen, &so->base);
return NULL;
}
@ -856,7 +881,7 @@ panfrost_resource_create_with_modifier(struct pipe_screen *screen,
panfrost_bo_create(dev, so->image.layout.data_size, flags, label);
if (!so->bo) {
FREE(so);
panfrost_resource_destroy(screen, &so->base);
return NULL;
}
@ -867,7 +892,7 @@ panfrost_resource_create_with_modifier(struct pipe_screen *screen,
if (drm_is_afbc(so->image.layout.modifier)) {
if (panfrost_resource_init_afbc_headers(so)) {
FREE(so);
panfrost_resource_destroy(screen, &so->base);
return NULL;
}
}
@ -910,31 +935,6 @@ panfrost_resource_create_with_modifiers(struct pipe_screen *screen,
return panfrost_resource_create(screen, template);
}
static void
panfrost_resource_destroy(struct pipe_screen *screen, struct pipe_resource *pt)
{
MESA_TRACE_FUNC();
struct panfrost_device *dev = pan_device(screen);
struct panfrost_resource *rsrc = (struct panfrost_resource *)pt;
if (rsrc->scanout)
renderonly_scanout_destroy(rsrc->scanout, dev->ro);
if (rsrc->shadow_image)
pipe_resource_reference(
(struct pipe_resource **)&rsrc->shadow_image, NULL);
if (rsrc->bo)
panfrost_bo_unreference(rsrc->bo);
free(rsrc->index_cache);
free(rsrc->damage.tile_map.data);
util_range_destroy(&rsrc->valid_buffer_range);
free(rsrc);
}
/* Most of the time we can do CPU-side transfers, but sometimes we need to use
* the 3D pipe for this. Let's wrap u_blitter to blit to/from staging textures.
* Code adapted from freedreno */