mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-12 04:53:18 -04:00
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: c322874710 ("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>
This commit is contained in:
committed by
Danilo Krummrich
parent
caa1bc2a0a
commit
c2256c044a
@@ -279,11 +279,25 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
|
||||
|
||||
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 = {
|
||||
|
||||
Reference in New Issue
Block a user