]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm/huge_memory: initialise workingset state before folio split
authorMatt Fleming <mfleming@cloudflare.com>
Sat, 25 Jul 2026 10:14:19 +0000 (11:14 +0100)
committerAndrew Morton <akpm@linux-foundation.org>
Wed, 5 Aug 2026 03:02:03 +0000 (20:02 -0700)
xas_try_split() adds __GFP_ACCOUNT for page-cache xa_nodes, but
__folio_split() leaves the xa_state's xa_lru unset.  That lets a live,
memcg-charged xa_node exist without being linked into the mapping's
shadow_nodes list_lru; when reclaim later walks the list_lru it trips
VM_WARN_ON(!css_is_dying()).

Use mapping_set_update() to install both the workingset update callback
and the shadow_nodes list_lru on the xa_state.

Link: https://lore.kernel.org/20260725101419.3938406-1-matt@readmodwrite.com
Fixes: 58729c04cf10 ("mm/huge_memory: add buddy allocator like (non-uniform) folio_split()")
Signed-off-by: Matt Fleming <mfleming@cloudflare.com>
Reported-by: syzbot+c5b060ce82921a2fd500@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c5b060ce82921a2fd500
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Kairui Song <ryncsn@gmail.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Nico Pache <npache@redhat.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/huge_memory.c

index f84fe7913d88fb5cf7e4eb7dffba2b02fc98b068..5d94fa4c74fdb6297da148726b14f86de71f1f85 100644 (file)
@@ -4076,7 +4076,7 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
                gfp_t gfp;
 
                mapping = folio->mapping;
-               min_order = mapping_min_folio_order(folio->mapping);
+               min_order = mapping_min_folio_order(mapping);
                if (new_order < min_order) {
                        ret = -EINVAL;
                        goto out;
@@ -4090,6 +4090,8 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
                        goto out;
                }
 
+               mapping_set_update(&xas, mapping);
+
                if (split_type == SPLIT_TYPE_UNIFORM) {
                        xas_set_order(&xas, folio->index, new_order);
                        xas_split_alloc(&xas, folio, old_order, gfp);