Linux cgroups development
 help / color / mirror / Atom feed
* [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
@ 2026-06-02  4:34 Lance Yang
  2026-06-02  4:38 ` Lance Yang
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Lance Yang @ 2026-06-02  4:34 UTC (permalink / raw)
  To: akpm
  Cc: david, ljs, shakeel.butt, mhocko, david, roman.gushchin,
	muchun.song, qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas,
	vbabka, ryncsn, zaslonko, gor, wangkefeng.wang, baolin.wang,
	baohua, dev.jain, npache, ryan.roberts, cgroups, linux-mm,
	linux-kernel, Lance Yang

From: Lance Yang <lance.yang@linux.dev>

deferred_split_count() returns the raw list_lru count. When the per-memcg,
per-node list is empty, that count is 0.

That skips scanning, but it does not tell memcg reclaim that the shrinker
is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
count callback reports SHRINK_EMPTY.

Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
cleared once the queue has drained.

Signed-off-by: Lance Yang <lance.yang@linux.dev>
---
 mm/huge_memory.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 72f6caf0fec6..62d598290c3b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
 static unsigned long deferred_split_count(struct shrinker *shrink,
 		struct shrink_control *sc)
 {
-	return list_lru_shrink_count(&deferred_split_lru, sc);
+	unsigned long count;
+
+	count = list_lru_shrink_count(&deferred_split_lru, sc);
+	return count ?: SHRINK_EMPTY;
 }
 
 static bool thp_underused(struct folio *folio)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02  4:34 [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain Lance Yang
@ 2026-06-02  4:38 ` Lance Yang
  2026-06-02 12:11   ` David Hildenbrand (Arm)
  2026-06-02 10:30 ` Usama Arif
  2026-06-02 20:37 ` Andrew Morton
  2 siblings, 1 reply; 9+ messages in thread
From: Lance Yang @ 2026-06-02  4:38 UTC (permalink / raw)
  To: akpm, hannes
  Cc: david, ljs, shakeel.butt, mhocko, david, roman.gushchin,
	muchun.song, qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas,
	vbabka, ryncsn, zaslonko, gor, wangkefeng.wang, baolin.wang,
	baohua, dev.jain, npache, ryan.roberts, cgroups, linux-mm,
	linux-kernel

Sorry, I missed Johannes in Cc ...

On 2026/6/2 12:34, Lance Yang wrote:
> From: Lance Yang <lance.yang@linux.dev>
> 
> deferred_split_count() returns the raw list_lru count. When the per-memcg,
> per-node list is empty, that count is 0.
> 
> That skips scanning, but it does not tell memcg reclaim that the shrinker
> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
> count callback reports SHRINK_EMPTY.
> 
> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
> cleared once the queue has drained.
> 
> Signed-off-by: Lance Yang <lance.yang@linux.dev>
> ---
>   mm/huge_memory.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 72f6caf0fec6..62d598290c3b 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
>   static unsigned long deferred_split_count(struct shrinker *shrink,
>   		struct shrink_control *sc)
>   {
> -	return list_lru_shrink_count(&deferred_split_lru, sc);
> +	unsigned long count;
> +
> +	count = list_lru_shrink_count(&deferred_split_lru, sc);
> +	return count ?: SHRINK_EMPTY;
>   }
>   
>   static bool thp_underused(struct folio *folio)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02  4:34 [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain Lance Yang
  2026-06-02  4:38 ` Lance Yang
@ 2026-06-02 10:30 ` Usama Arif
  2026-06-02 20:37 ` Andrew Morton
  2 siblings, 0 replies; 9+ messages in thread
From: Usama Arif @ 2026-06-02 10:30 UTC (permalink / raw)
  To: Lance Yang, akpm
  Cc: david, ljs, shakeel.butt, mhocko, david, roman.gushchin,
	muchun.song, qi.zheng, yosry.ahmed, ziy, liam, kas, vbabka,
	ryncsn, zaslonko, gor, wangkefeng.wang, baolin.wang, baohua,
	dev.jain, npache, ryan.roberts, cgroups, linux-mm, linux-kernel



On 02/06/2026 05:34, Lance Yang wrote:
> From: Lance Yang <lance.yang@linux.dev>
> 
> deferred_split_count() returns the raw list_lru count. When the per-memcg,
> per-node list is empty, that count is 0.
> 
> That skips scanning, but it does not tell memcg reclaim that the shrinker
> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
> count callback reports SHRINK_EMPTY.
> 
> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
> cleared once the queue has drained.
> 
> Signed-off-by: Lance Yang <lance.yang@linux.dev>

Same as slab, workingset and others.

Acked-by: Usama Arif <usama.arif@linux.dev>





^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02  4:38 ` Lance Yang
@ 2026-06-02 12:11   ` David Hildenbrand (Arm)
  2026-06-02 12:47     ` Lance Yang
  0 siblings, 1 reply; 9+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-02 12:11 UTC (permalink / raw)
  To: Lance Yang, akpm, hannes
  Cc: ljs, shakeel.butt, mhocko, david, roman.gushchin, muchun.song,
	qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas, vbabka, ryncsn,
	zaslonko, gor, wangkefeng.wang, baolin.wang, baohua, dev.jain,
	npache, ryan.roberts, cgroups, linux-mm, linux-kernel

On 6/2/26 06:38, Lance Yang wrote:
> Sorry, I missed Johannes in Cc ...
> 
> On 2026/6/2 12:34, Lance Yang wrote:
>> From: Lance Yang <lance.yang@linux.dev>
>>
>> deferred_split_count() returns the raw list_lru count. When the per-memcg,
>> per-node list is empty, that count is 0.
>>
>> That skips scanning, but it does not tell memcg reclaim that the shrinker
>> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
>> count callback reports SHRINK_EMPTY.

What's the effect of that? Would we consider it a fix that we'd want to backport?

>>
>> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
>> cleared once the queue has drained.
>>
>> Signed-off-by: Lance Yang <lance.yang@linux.dev>
>> ---
>>   mm/huge_memory.c | 5 ++++-
>>   1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>> index 72f6caf0fec6..62d598290c3b 100644
>> --- a/mm/huge_memory.c
>> +++ b/mm/huge_memory.c
>> @@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool
>> partially_mapped)
>>   static unsigned long deferred_split_count(struct shrinker *shrink,
>>           struct shrink_control *sc)
>>   {
>> -    return list_lru_shrink_count(&deferred_split_lru, sc);
>> +    unsigned long count;
>> +
>> +    count = list_lru_shrink_count(&deferred_split_lru, sc);
>> +    return count ?: SHRINK_EMPTY;
>>   }
>>     static bool thp_underused(struct folio *folio)
> 

This is against Johannes' work, right?

If this is a fix, likely it would be fixing 87eaceb3faa5 ("mm: thp: make
deferred split shrinker memcg aware"), right?

-- 
Cheers,

David

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02 12:11   ` David Hildenbrand (Arm)
@ 2026-06-02 12:47     ` Lance Yang
  2026-06-02 17:33       ` David Hildenbrand (Arm)
  0 siblings, 1 reply; 9+ messages in thread
From: Lance Yang @ 2026-06-02 12:47 UTC (permalink / raw)
  To: David Hildenbrand (Arm), akpm, hannes
  Cc: ljs, shakeel.butt, mhocko, david, roman.gushchin, muchun.song,
	qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas, vbabka, ryncsn,
	zaslonko, gor, wangkefeng.wang, baolin.wang, baohua, dev.jain,
	npache, ryan.roberts, cgroups, linux-mm, linux-kernel



On 2026/6/2 20:11, David Hildenbrand (Arm) wrote:
> On 6/2/26 06:38, Lance Yang wrote:
>> Sorry, I missed Johannes in Cc ...
>>
>> On 2026/6/2 12:34, Lance Yang wrote:
>>> From: Lance Yang <lance.yang@linux.dev>
>>>
>>> deferred_split_count() returns the raw list_lru count. When the per-memcg,
>>> per-node list is empty, that count is 0.
>>>
>>> That skips scanning, but it does not tell memcg reclaim that the shrinker
>>> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
>>> count callback reports SHRINK_EMPTY.
> 
> What's the effect of that? Would we consider it a fix that we'd want to backport?

Just a stale memcg shrinker bit :) I'd treat this patch as a small
cleanup.

Once the queue is empty, count_objects() returns 0. That skips the scan,
but shrink_slab_memcg() only clears the bit on SHRINK_EMPTY, not 0.

So memcg reclaim can keep calling the shrinker even though there is
nothing on that queue.

>>>
>>> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
>>> cleared once the queue has drained.
>>>
>>> Signed-off-by: Lance Yang <lance.yang@linux.dev>
>>> ---
>>>    mm/huge_memory.c | 5 ++++-
>>>    1 file changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>>> index 72f6caf0fec6..62d598290c3b 100644
>>> --- a/mm/huge_memory.c
>>> +++ b/mm/huge_memory.c
>>> @@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool
>>> partially_mapped)
>>>    static unsigned long deferred_split_count(struct shrinker *shrink,
>>>            struct shrink_control *sc)
>>>    {
>>> -    return list_lru_shrink_count(&deferred_split_lru, sc);
>>> +    unsigned long count;
>>> +
>>> +    count = list_lru_shrink_count(&deferred_split_lru, sc);
>>> +    return count ?: SHRINK_EMPTY;
>>>    }
>>>      static bool thp_underused(struct folio *folio)
>>
> 
> This is against Johannes' work, right?

Yep, I noticed it there, but the behavior is older.

> If this is a fix, likely it would be fixing 87eaceb3faa5 ("mm: thp: make
> deferred split shrinker memcg aware"), right?

No missed reclaim, just some extra reclaim work :)

Cheers, Lance

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02 12:47     ` Lance Yang
@ 2026-06-02 17:33       ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 9+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-02 17:33 UTC (permalink / raw)
  To: Lance Yang, akpm, hannes
  Cc: ljs, shakeel.butt, mhocko, david, roman.gushchin, muchun.song,
	qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas, vbabka, ryncsn,
	zaslonko, gor, wangkefeng.wang, baolin.wang, baohua, dev.jain,
	npache, ryan.roberts, cgroups, linux-mm, linux-kernel

On 6/2/26 14:47, Lance Yang wrote:
> 
> 
> On 2026/6/2 20:11, David Hildenbrand (Arm) wrote:
>> On 6/2/26 06:38, Lance Yang wrote:
>>> Sorry, I missed Johannes in Cc ...
>>>
>>
>> What's the effect of that? Would we consider it a fix that we'd want to backport?
> 
> Just a stale memcg shrinker bit :) I'd treat this patch as a small
> cleanup.
> 
> Once the queue is empty, count_objects() returns 0. That skips the scan,
> but shrink_slab_memcg() only clears the bit on SHRINK_EMPTY, not 0.
> 
> So memcg reclaim can keep calling the shrinker even though there is
> nothing on that queue.
> 
>>>
>>
>> This is against Johannes' work, right?
> 
> Yep, I noticed it there, but the behavior is older.
> 
>> If this is a fix, likely it would be fixing 87eaceb3faa5 ("mm: thp: make
>> deferred split shrinker memcg aware"), right?
> 
> No missed reclaim, just some extra reclaim work :)

Thanks for clarifying! :)

Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>

-- 
Cheers,

David

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02  4:34 [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain Lance Yang
  2026-06-02  4:38 ` Lance Yang
  2026-06-02 10:30 ` Usama Arif
@ 2026-06-02 20:37 ` Andrew Morton
  2026-06-03  2:00   ` Lance Yang
  2 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2026-06-02 20:37 UTC (permalink / raw)
  To: Lance Yang
  Cc: david, ljs, shakeel.butt, mhocko, david, roman.gushchin,
	muchun.song, qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas,
	vbabka, ryncsn, zaslonko, gor, wangkefeng.wang, baolin.wang,
	baohua, dev.jain, npache, ryan.roberts, cgroups, linux-mm,
	linux-kernel, Johannes Weiner

On Tue,  2 Jun 2026 12:34:53 +0800 Lance Yang <lance.yang@linux.dev> wrote:

> From: Lance Yang <lance.yang@linux.dev>
> 
> deferred_split_count() returns the raw list_lru count. When the per-memcg,
> per-node list is empty, that count is 0.
> 
> That skips scanning, but it does not tell memcg reclaim that the shrinker
> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
> count callback reports SHRINK_EMPTY.
> 
> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
> cleared once the queue has drained.
> 
> Signed-off-by: Lance Yang <lance.yang@linux.dev>
> ---
>  mm/huge_memory.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 72f6caf0fec6..62d598290c3b 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
>  static unsigned long deferred_split_count(struct shrinker *shrink,
>  		struct shrink_control *sc)
>  {
> -	return list_lru_shrink_count(&deferred_split_lru, sc);
> +	unsigned long count;
> +
> +	count = list_lru_shrink_count(&deferred_split_lru, sc);
> +	return count ?: SHRINK_EMPTY;
>  }
>  
>  static bool thp_underused(struct folio *folio)

Should this be handled as a fix against hannes's "mm: switch deferred
split shrinker to list_lru"?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-02 20:37 ` Andrew Morton
@ 2026-06-03  2:00   ` Lance Yang
  2026-06-03  8:02     ` David Hildenbrand (Arm)
  0 siblings, 1 reply; 9+ messages in thread
From: Lance Yang @ 2026-06-03  2:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: david, ljs, shakeel.butt, mhocko, david, roman.gushchin,
	muchun.song, qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas,
	vbabka, ryncsn, zaslonko, gor, wangkefeng.wang, baolin.wang,
	baohua, dev.jain, npache, ryan.roberts, cgroups, linux-mm,
	linux-kernel, Johannes Weiner



On 2026/6/3 04:37, Andrew Morton wrote:
> On Tue,  2 Jun 2026 12:34:53 +0800 Lance Yang <lance.yang@linux.dev> wrote:
> 
>> From: Lance Yang <lance.yang@linux.dev>
>>
>> deferred_split_count() returns the raw list_lru count. When the per-memcg,
>> per-node list is empty, that count is 0.
>>
>> That skips scanning, but it does not tell memcg reclaim that the shrinker
>> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
>> count callback reports SHRINK_EMPTY.
>>
>> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
>> cleared once the queue has drained.
>>
>> Signed-off-by: Lance Yang <lance.yang@linux.dev>
>> ---
>>   mm/huge_memory.c | 5 ++++-
>>   1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>> index 72f6caf0fec6..62d598290c3b 100644
>> --- a/mm/huge_memory.c
>> +++ b/mm/huge_memory.c
>> @@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
>>   static unsigned long deferred_split_count(struct shrinker *shrink,
>>   		struct shrink_control *sc)
>>   {
>> -	return list_lru_shrink_count(&deferred_split_lru, sc);
>> +	unsigned long count;
>> +
>> +	count = list_lru_shrink_count(&deferred_split_lru, sc);
>> +	return count ?: SHRINK_EMPTY;
>>   }
>>   
>>   static bool thp_underused(struct folio *folio)
> 
> Should this be handled as a fix against hannes's "mm: switch deferred
> split shrinker to list_lru"?

Hmm ... I noticed this while looking at Johannes' work, but the
behavior is older than that ...

We also discussed the Fixes tag earlier[1] and decided to leave it
out. There is no missed reclaim, only some extra reclaim work :)

[1] 
https://lore.kernel.org/linux-mm/63797977-1c18-4885-8099-f5c21c80da39@linux.dev/

Cheers, Lance

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain
  2026-06-03  2:00   ` Lance Yang
@ 2026-06-03  8:02     ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 9+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-03  8:02 UTC (permalink / raw)
  To: Lance Yang, Andrew Morton
  Cc: ljs, shakeel.butt, mhocko, david, roman.gushchin, muchun.song,
	qi.zheng, yosry.ahmed, ziy, liam, usama.arif, kas, vbabka, ryncsn,
	zaslonko, gor, wangkefeng.wang, baolin.wang, baohua, dev.jain,
	npache, ryan.roberts, cgroups, linux-mm, linux-kernel,
	Johannes Weiner

On 6/3/26 04:00, Lance Yang wrote:
> 
> 
> On 2026/6/3 04:37, Andrew Morton wrote:
>> On Tue,  2 Jun 2026 12:34:53 +0800 Lance Yang <lance.yang@linux.dev> wrote:
>>
>>> From: Lance Yang <lance.yang@linux.dev>
>>>
>>> deferred_split_count() returns the raw list_lru count. When the per-memcg,
>>> per-node list is empty, that count is 0.
>>>
>>> That skips scanning, but it does not tell memcg reclaim that the shrinker
>>> is empty. shrink_slab_memcg() only clears the memcg shrinker bit when the
>>> count callback reports SHRINK_EMPTY.
>>>
>>> Return SHRINK_EMPTY for an empty deferred split list, so the bit can be
>>> cleared once the queue has drained.
>>>
>>> Signed-off-by: Lance Yang <lance.yang@linux.dev>
>>> ---
>>>   mm/huge_memory.c | 5 ++++-
>>>   1 file changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>>> index 72f6caf0fec6..62d598290c3b 100644
>>> --- a/mm/huge_memory.c
>>> +++ b/mm/huge_memory.c
>>> @@ -4397,7 +4397,10 @@ void deferred_split_folio(struct folio *folio, bool
>>> partially_mapped)
>>>   static unsigned long deferred_split_count(struct shrinker *shrink,
>>>           struct shrink_control *sc)
>>>   {
>>> -    return list_lru_shrink_count(&deferred_split_lru, sc);
>>> +    unsigned long count;
>>> +
>>> +    count = list_lru_shrink_count(&deferred_split_lru, sc);
>>> +    return count ?: SHRINK_EMPTY;
>>>   }
>>>     static bool thp_underused(struct folio *folio)
>>
>> Should this be handled as a fix against hannes's "mm: switch deferred
>> split shrinker to list_lru"?
> 
> Hmm ... I noticed this while looking at Johannes' work, but the
> behavior is older than that ...
> 
> We also discussed the Fixes tag earlier[1] and decided to leave it
> out. There is no missed reclaim, only some extra reclaim work :)

Right, I conclude that this can be a separate patch on top.

-- 
Cheers,

David

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-06-03  8:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02  4:34 [PATCH 1/1] mm/thp: clear deferred split shrinker bits when queues drain Lance Yang
2026-06-02  4:38 ` Lance Yang
2026-06-02 12:11   ` David Hildenbrand (Arm)
2026-06-02 12:47     ` Lance Yang
2026-06-02 17:33       ` David Hildenbrand (Arm)
2026-06-02 10:30 ` Usama Arif
2026-06-02 20:37 ` Andrew Morton
2026-06-03  2:00   ` Lance Yang
2026-06-03  8:02     ` David Hildenbrand (Arm)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox