mm/huge_memory: Initialise workingset state before folio split
Subsystems (3)
PATCH 1/1 mm/huge_memory: Initialise workingset state before folio split
From: Matt Fleming <[email protected]>
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.
--- mm/huge_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
mm/huge_memory.c +2 -1
@@ -4033,7 +4033,8 @@ 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); +mapping_set_update (&xas, mapping); + min_order =mapping_min_folio_order (mapping);if (new_order < min_order) { ret = -EINVAL ; goto out;
Signature · 1 line
2.43.0
Zi Yan
reviewerQuoted 4 lines · Matt Fleming
From: Matt Fleming <[email protected]>
xas_try_split()adds__GFP_ACCOUNTfor page-cachexa_nodes, but__folio_split()leaves the xa_state'sxa_lruunset. That lets a live,
But mapping_set_update() is not required for xas_split_alloc() and xas_split(), or at least nothing triggered for uniform split path. Why?
xas_split_alloc() uses
gfp = current_gfp_context(mapping_gfp_mask(mapping) & GFP_RECLAIM_MASK), whereas xas_try_split() starts with GFP_NOWAIT and follows xas_nomem() by adding __GFP_ACCOUNT if XA_FLAGS_ACCOUNT is set.
Should xas_split_alloc() also take a gfp input and the caller gets gfp the same way as xas_split_alloc()?
Quoted 32 lines
memcg-charged
xa_nodeexist without being linked into the mapping'sshadow_nodeslist_lru; when reclaim later walks thelist_lruit trips VM_WARN_ON(!css_is_dying()).Use
mapping_set_update()to install both the workingset update callback and theshadow_nodeslist_lruon thexa_state.Reported-by [email protected]Fixes 58729c04cf10 ("mm/huge_memory: add buddy allocator like (non-uniform) folio_split()")Signed-off-by Matt Fleming <[email protected]>--- mm/huge_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)mm/huge_memory.c +2
-1@@ -4033,7 +4033,8 @@ 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); +mapping_set_update (&xas, mapping); + min_order =mapping_min_folio_order (mapping);if (new_order < min_order) { ret = -EINVAL ; goto out;Signature · 1 line
2.43.0
Best Regards,
Yan, Zi
Zi Yan
reviewerUse Lorenzo’s current email.
Quoted 41 lines · Zi Yan
Quoted 4 lines · Matt Fleming
From: Matt Fleming <[email protected]>
xas_try_split()adds__GFP_ACCOUNTfor page-cachexa_nodes, but__folio_split()leaves the xa_state'sxa_lruunset. That lets a live,But
mapping_set_update()is not required forxas_split_alloc()andxas_split(), or at least nothing triggered for uniform split path. Why?
xas_split_alloc()uses
gfp =current_gfp_context(mapping_gfp_mask(mapping) & GFP_RECLAIM_MASK), whereasxas_try_split()starts withGFP_NOWAITand followsxas_nomem()by adding__GFP_ACCOUNTifXA_FLAGS_ACCOUNTis set.Should
xas_split_alloc()also take a gfp input and the caller gets gfp the same way asxas_split_alloc()?Quoted 23 lines
memcg-charged
xa_nodeexist without being linked into the mapping'sshadow_nodeslist_lru; when reclaim later walks thelist_lruit trips VM_WARN_ON(!css_is_dying()).Use
mapping_set_update()to install both the workingset update callback and theshadow_nodeslist_lruon thexa_state.Reported-by [email protected]Fixes 58729c04cf10 ("mm/huge_memory: add buddy allocator like (non-uniform) folio_split()")Signed-off-by Matt Fleming <[email protected]>--- mm/huge_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)mm/huge_memory.c +0
-0@@ -4033,7 +4033,8 @@ static int __folio_split(struct folio *folio, unsigned int new_order,gfp_t gfp;
Quoted 13 lines
Quoted 9 lines
mm/huge_memory.c +2
-1mapping = folio->mapping; - min_order =mapping_min_folio_order (folio->mapping); +mapping_set_update (&xas, mapping); + min_order =mapping_min_folio_order (mapping);if (new_order < min_order) { ret = -EINVAL ; goto out;Signature · 1 line
2.43.0Best Regards,
Yan, Zi
Best Regards,
Yan, Zi
Quoted 21 lines · Zi Yan
Use Lorenzo’s current email.
Quoted 17 lines · Zi Yan
Quoted 4 lines · Matt Fleming
From: Matt Fleming <[email protected]>
xas_try_split()adds__GFP_ACCOUNTfor page-cachexa_nodes, but__folio_split()leaves the xa_state'sxa_lruunset. That lets a live,But
mapping_set_update()is not required forxas_split_alloc()andxas_split(), or at least nothing triggered for uniform split path. Why?
xas_split_alloc()uses
gfp =current_gfp_context(mapping_gfp_mask(mapping) & GFP_RECLAIM_MASK), whereasxas_try_split()starts withGFP_NOWAITand followsxas_nomem()by adding__GFP_ACCOUNTifXA_FLAGS_ACCOUNTis set.Should
xas_split_alloc()also take a gfp input and the caller gets gfp the same way asxas_split_alloc()?
xas_try_split() is called under the xarray lock with irq disabled, so it cannot accept arbitrary gfp. And xas_split_alloc() is the only one does not do
if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
gfp |= __GFP_ACCOUNT;
the others, xas_nomem(), __xas_nomem(), and xas_alloc() all have it. Commit 7b785645e8f13 ("mm: fix page cache convergence regression") added the __GFP_ACCOUNT statement. I will send a patch to add it to xas_split_alloc() with Fixes: 6b24ca4a1a8d4 ("mm: Use multi-index entries in the page cache")
In sum, I think this patch does the right thing. And Sashiko pointed out this issue before[1].
[1] https://sashiko.dev/#/patchset/[email protected]
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
memcg-charged
xa_nodeexist without being linked into the mapping'sshadow_nodeslist_lru; when reclaim later walks thelist_lruit trips VM_WARN_ON(!css_is_dying()).Use
mapping_set_update()to install both the workingset update callback and theshadow_nodeslist_lruon thexa_state.Reported-by [email protected]Fixes 58729c04cf10 ("mm/huge_memory: add buddy allocator like (non-uniform) folio_split()")Signed-off-by Matt Fleming <[email protected]>--- mm/huge_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)mm/huge_memory.c +0
-0@@ -4033,7 +4033,8 @@ static int __folio_split(struct folio *folio, unsigned int new_order,gfp_t gfp;
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
mm/huge_memory.c +2
-1mapping = folio->mapping; - min_order =mapping_min_folio_order (folio->mapping); +mapping_set_update (&xas, mapping); + min_order =mapping_min_folio_order (mapping);if (new_order < min_order) { ret = -EINVAL ; goto out;Signature · 1 line
2.43.0
mapping_set_update() probably can be delayed right before the if block containing xas_split_alloc(). Otherwise, LGTM. Thanks.
Best Regards,
Yan, Zi