From 801078cbf8e69f0b285c908c4017257798d0940a Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Fri, 26 Jul 2024 00:42:59 +0200 Subject: [PATCH] nouveau: handle realloc failure inside cli_kref_set Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/11477 Fixes: 821f4c8d99a ("nouveau: import libdrm_nouveau") Part-of: --- src/gallium/drivers/nouveau/nouveau_winsys.h | 3 +- src/gallium/winsys/nouveau/drm/nouveau.c | 35 +++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/gallium/drivers/nouveau/nouveau_winsys.h b/src/gallium/drivers/nouveau/nouveau_winsys.h index ccd90c03b4b..cad8dc3e620 100644 --- a/src/gallium/drivers/nouveau/nouveau_winsys.h +++ b/src/gallium/drivers/nouveau/nouveau_winsys.h @@ -94,7 +94,8 @@ PUSH_KICK(struct nouveau_pushbuf *push) { struct nouveau_pushbuf_priv *ppush = push->user_priv; simple_mtx_lock(&ppush->screen->fence.lock); - nouveau_pushbuf_kick(push); + int ASSERTED ret = nouveau_pushbuf_kick(push); + assert(!ret); simple_mtx_unlock(&ppush->screen->fence.lock); } diff --git a/src/gallium/winsys/nouveau/drm/nouveau.c b/src/gallium/winsys/nouveau/drm/nouveau.c index 4bf35f46cac..fc9332b205a 100644 --- a/src/gallium/winsys/nouveau/drm/nouveau.c +++ b/src/gallium/winsys/nouveau/drm/nouveau.c @@ -848,13 +848,18 @@ cli_kref_get(struct nouveau_client *client, struct nouveau_bo *bo) return kref; } -static inline void +static inline int cli_kref_set(struct nouveau_client *client, struct nouveau_bo *bo, struct drm_nouveau_gem_pushbuf_bo *kref, struct nouveau_pushbuf *push) { struct nouveau_client_priv *pcli = nouveau_client(client); if (pcli->kref_nr <= bo->handle) { - pcli->kref = realloc(pcli->kref, sizeof(*pcli->kref) * bo->handle * 2); + void *new_ptr = realloc(pcli->kref, sizeof(*pcli->kref) * bo->handle * 2); + if (!new_ptr) { + err("Failed to realloc memory, expect faulty rendering.\n"); + return -ENOMEM; + } + pcli->kref = new_ptr; while (pcli->kref_nr < bo->handle * 2) { pcli->kref[pcli->kref_nr].kref = NULL; pcli->kref[pcli->kref_nr].push = NULL; @@ -863,6 +868,7 @@ cli_kref_set(struct nouveau_client *client, struct nouveau_bo *bo, } pcli->kref[bo->handle].kref = kref; pcli->kref[bo->handle].push = push; + return 0; } int @@ -1203,7 +1209,9 @@ pushbuf_flush(struct nouveau_pushbuf *push) kref = krec->buffer; for (i = 0; i < krec->nr_buffer; i++, kref++) { struct nouveau_bo *bo = (void *)(unsigned long)kref->user_priv; - cli_kref_set(push->client, bo, NULL, NULL); + ret = cli_kref_set(push->client, bo, NULL, NULL); + if (ret) + return ret; nouveau_bo_ref(NULL, &bo); } @@ -1299,6 +1307,7 @@ pushbuf_kref(struct nouveau_pushbuf *push, struct nouveau_bo *bo, uint32_t flags struct nouveau_pushbuf *fpush; struct drm_nouveau_gem_pushbuf_bo *kref; uint32_t domains, domains_wr, domains_rd; + int ret; domains = 0; if (flags & NOUVEAU_BO_VRAM) @@ -1354,7 +1363,9 @@ pushbuf_kref(struct nouveau_pushbuf *push, struct nouveau_bo *bo, uint32_t flags else kref->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; - cli_kref_set(push->client, bo, kref, push); + ret = cli_kref_set(push->client, bo, kref, push); + if (ret) + return NULL; p_atomic_inc(&nouveau_bo(bo)->refcnt); } @@ -1401,22 +1412,26 @@ pushbuf_krel(struct nouveau_pushbuf *push, struct nouveau_bo *bo, return reloc; } -static void +static int pushbuf_refn_fail(struct nouveau_pushbuf *push, int sref, int srel) { struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); struct nouveau_pushbuf_krec *krec = nvpb->krec; struct drm_nouveau_gem_pushbuf_bo *kref; + int ret; kref = krec->buffer + sref; while (krec->nr_buffer-- > sref) { struct nouveau_bo *bo = (void *)(unsigned long)kref->user_priv; - cli_kref_set(push->client, bo, NULL, NULL); + ret = cli_kref_set(push->client, bo, NULL, NULL); + if (ret) + return ret; nouveau_bo_ref(NULL, &bo); kref++; } krec->nr_buffer = sref; krec->nr_reloc = srel; + return 0; } static int @@ -1438,7 +1453,9 @@ pushbuf_refn(struct nouveau_pushbuf *push, bool retry, } if (ret) { - pushbuf_refn_fail(push, sref, krec->nr_reloc); + ret = pushbuf_refn_fail(push, sref, krec->nr_reloc); + if (ret) + return ret; if (retry) { pushbuf_flush(push); nouveau_pushbuf_space(push, 0, 0, 0); @@ -1489,7 +1506,9 @@ pushbuf_validate(struct nouveau_pushbuf *push, bool retry) list_inithead(&bctx->pending); if (ret) { - pushbuf_refn_fail(push, sref, srel); + ret = pushbuf_refn_fail(push, sref, srel); + if (ret) + return ret; if (retry) { pushbuf_flush(push); return pushbuf_validate(push, false);