mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
mm/mremap: fix moving PUD leaves
pud_none_or_clear_bad() only really works on page tables. PUD leaves confuse the check and make us clear the page table entry and print a warning. Since commitaed877c2b4("device/dax: properly refcount device dax pages when mapping"), this also leaks device-DAX folio references, mapcounts and RSS accounting, resulting in "Bad rss-counter state" warnings on exit. Allow PUD leaves in get_old_pud(). If a PUD leaf cannot be moved as a whole or the move fails, split it. This unmaps it with proper accounting instead of treating the leaf entry as a PMD table. Keep using pud_trans_huge() for now, in the future this code should be cleaned up to just check for PUD leaves. Fix generated by an LLM and sent by Josef Bacik in private. Fixes:a00cc7d9dd("mm, x86: add support for PUD-sized transparent hugepages") Cc: stable@vger.kernel.org Signed-off-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org> [ david: fallthrough after splitting ] Reviewed-by: Pedro Falcato <pfalcato@suse.de> Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com> Link: https://patch.msgid.link/20261031-fixes_core-v3-32-d6437171ecc3@kernel.org Reviewed-by: Lance Yang <lance.yang@linux.dev> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
This commit is contained in:
parent
402882943d
commit
440c877975
|
|
@ -87,7 +87,7 @@ static pud_t *get_old_pud(struct mm_struct *mm, unsigned long addr)
|
|||
return NULL;
|
||||
|
||||
pud = pud_offset(p4d, addr);
|
||||
if (pud_none_or_clear_bad(pud))
|
||||
if (!pud_trans_huge(*pud) && pud_none_or_clear_bad(pud))
|
||||
return NULL;
|
||||
|
||||
return pud;
|
||||
|
|
@ -847,11 +847,10 @@ unsigned long move_page_tables(struct pagetable_move_control *pmc)
|
|||
if (!new_pud)
|
||||
break;
|
||||
if (pud_trans_huge(*old_pud)) {
|
||||
if (extent == HPAGE_PUD_SIZE) {
|
||||
move_pgt_entry(pmc, HPAGE_PUD, old_pud, new_pud);
|
||||
/* We ignore and continue on error? */
|
||||
if (extent == HPAGE_PUD_SIZE &&
|
||||
move_pgt_entry(pmc, HPAGE_PUD, old_pud, new_pud))
|
||||
continue;
|
||||
}
|
||||
split_huge_pud(pmc->old, old_pud, pmc->old_addr);
|
||||
} else if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) && extent == PUD_SIZE) {
|
||||
if (move_pgt_entry(pmc, NORMAL_PUD, old_pud, new_pud))
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user