nouveau: handle realloc failure inside cli_kref_set

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/11477
Fixes: 821f4c8d99 ("nouveau: import libdrm_nouveau")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30374>
This commit is contained in:
Karol Herbst 2024-07-26 00:42:59 +02:00 committed by Marge Bot
parent f8bf9f07b6
commit 801078cbf8
2 changed files with 29 additions and 9 deletions

View file

@ -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);
}

View file

@ -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);