summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhenhao Wan <whi4ed0g@gmail.com>2026-08-11 22:28:51 +0800
committerDanilo Krummrich <dakr@kernel.org>2026-09-01 11:09:24 +0200
commitc2256c044a1df39c8aad4dd2d6f709b2533e2d7a (patch)
treec3850fc14a1acd9e66ddab6bcba7534b28d242c2
parentcaa1bc2a0a6ca19dcb90bbf88208b0fe2decd66f (diff)
downloadlinux-next-c2256c044a1df39c8aad4dd2d6f709b2533e2d7a.tar.gz
linux-next-c2256c044a1df39c8aad4dd2d6f709b2533e2d7a.zip
drm/nouveau/dmem: fix callocated underflow on large folio split
nouveau_dmem_folio_free() drops chunk->callocated once per freed folio, while a large (compound) device-private folio is only counted once when it is allocated. When such a folio is split, the mm core invokes ->folio_split() (nouveau_dmem_folio_split()) once for each new sub-folio, but the hook only fixes up the sub-folio metadata and leaves chunk->callocated unchanged. Each resulting sub-folio is later freed separately, so after a split the single allocation (+1) is met by N frees (-N), leaving chunk->callocated short by N-1. On the first split/free cycle it underflows: WARN_ON(!chunk->callocated) fires, the unsigned counter wraps and never returns to zero, so the chunk can no longer be reclaimed (nouveau_dmem_fini() also warns on the leaked count). Account for the new sub-folio in the split hook, under the same lock as nouveau_dmem_folio_free(), so the count stays balanced. Fixes: c32287471077 ("gpu/drm/nouveau: enable THP support for GPU memory migration") Reported-by: Yuhao Jiang <danisjiang@gmail.com> Assisted-by: Claude:claude-opus-5 Cc: stable@vger.kernel.org Signed-off-by: Zhenhao Wan <whi4ed0g@gmail.com> Reviewed-by: Lyude Paul <lyude@redhat.com> Link: https://patch.msgid.link/20260811-b4-nouveau-dmem-thp-fixes-v1-2-2cdf9860af2a@gmail.com Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dmem.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
index d2abee3efb9a..ad4570c50be7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -279,11 +279,25 @@ err:
static void nouveau_dmem_folio_split(struct folio *head, struct folio *tail)
{
+ struct nouveau_dmem_chunk *chunk;
+ struct nouveau_dmem *dmem;
+
if (tail == NULL)
return;
tail->pgmap = head->pgmap;
tail->mapping = head->mapping;
folio_set_zone_device_data(tail, folio_zone_device_data(head));
+
+ /*
+ * The split hands out a new independently-freeable folio that will
+ * later be released via nouveau_dmem_folio_free(); account for it so
+ * chunk->callocated stays balanced.
+ */
+ chunk = nouveau_page_to_chunk(&head->page);
+ dmem = chunk->drm->dmem;
+ spin_lock(&dmem->lock);
+ chunk->callocated++;
+ spin_unlock(&dmem->lock);
}
static const struct dev_pagemap_ops nouveau_dmem_pagemap_ops = {