[PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork

Donet Tom posted 3 patches 2 weeks, 2 days ago
There is a newer version of this series
[PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Donet Tom 2 weeks, 2 days ago
Currently, the KSM-related counters in `mm_struct`, such as
`ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
inherited by the child process during fork. This results in inconsistent
accounting.

When a process uses KSM, identical pages are merged and an rmap item is
created for each merged page. The `ksm_merging_pages` and
`ksm_rmap_items` counters are updated accordingly. However, after a
fork, these counters are copied to the child while the corresponding
rmap items are not. As a result, when the child later triggers an
unmerge, there are no rmap items present in the child, so the counters
remain stale, leading to incorrect accounting.

A similar issue exists with `ksm_zero_pages`, which maintains both a
global counter and a per-process counter. During fork, the per-process
counter is inherited by the child, but the global counter is not
incremented. Since the child also references zero pages, the global
counter should be updated as well. Otherwise, during zero-page unmerge,
both the global and per-process counters are decremented, causing the
global counter to become inconsistent.

To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
during fork, and the global ksm_zero_pages counter is updated with the
per-process ksm_zero_pages value inherited by the child. This ensures
that KSM statistics remain accurate and reflect the activity of each
process correctly.

Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
cc: stable@vger.kernel.org # v6.6
Signed-off-by: Donet Tom <donettom@linux.ibm.com>
---
 include/linux/ksm.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/include/linux/ksm.h b/include/linux/ksm.h
index 22e67ca7cba3..067538fc4d58 100644
--- a/include/linux/ksm.h
+++ b/include/linux/ksm.h
@@ -56,8 +56,14 @@ static inline long mm_ksm_zero_pages(struct mm_struct *mm)
 static inline void ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
 {
 	/* Adding mm to ksm is best effort on fork. */
-	if (mm_flags_test(MMF_VM_MERGEABLE, oldmm))
+	if (mm_flags_test(MMF_VM_MERGEABLE, oldmm)) {
+		long nr_ksm_zero_pages = atomic_long_read(&mm->ksm_zero_pages);
+
+		mm->ksm_merging_pages = 0;
+		mm->ksm_rmap_items = 0;
+		atomic_long_add(nr_ksm_zero_pages, &ksm_zero_pages);
 		__ksm_enter(mm);
+	}
 }
 
 static inline int ksm_execve(struct mm_struct *mm)
-- 
2.51.0
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Chengming Zhou 2 weeks, 1 day ago
On 2025/9/15 23:03, Donet Tom wrote:
> Currently, the KSM-related counters in `mm_struct`, such as
> `ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
> inherited by the child process during fork. This results in inconsistent
> accounting.
> 
> When a process uses KSM, identical pages are merged and an rmap item is
> created for each merged page. The `ksm_merging_pages` and
> `ksm_rmap_items` counters are updated accordingly. However, after a
> fork, these counters are copied to the child while the corresponding
> rmap items are not. As a result, when the child later triggers an
> unmerge, there are no rmap items present in the child, so the counters
> remain stale, leading to incorrect accounting.
> 
> A similar issue exists with `ksm_zero_pages`, which maintains both a
> global counter and a per-process counter. During fork, the per-process
> counter is inherited by the child, but the global counter is not
> incremented. Since the child also references zero pages, the global
> counter should be updated as well. Otherwise, during zero-page unmerge,
> both the global and per-process counters are decremented, causing the
> global counter to become inconsistent.
> 
> To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
> during fork, and the global ksm_zero_pages counter is updated with the
> per-process ksm_zero_pages value inherited by the child. This ensures
> that KSM statistics remain accurate and reflect the activity of each
> process correctly.
> 
> Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
> Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
> Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
> cc: stable@vger.kernel.org # v6.6
> Signed-off-by: Donet Tom <donettom@linux.ibm.com>

Reviewed-by: Chengming Zhou <chengming.zhou@linux.dev>

Thanks.

> ---
>   include/linux/ksm.h | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/ksm.h b/include/linux/ksm.h
> index 22e67ca7cba3..067538fc4d58 100644
> --- a/include/linux/ksm.h
> +++ b/include/linux/ksm.h
> @@ -56,8 +56,14 @@ static inline long mm_ksm_zero_pages(struct mm_struct *mm)
>   static inline void ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
>   {
>   	/* Adding mm to ksm is best effort on fork. */
> -	if (mm_flags_test(MMF_VM_MERGEABLE, oldmm))
> +	if (mm_flags_test(MMF_VM_MERGEABLE, oldmm)) {
> +		long nr_ksm_zero_pages = atomic_long_read(&mm->ksm_zero_pages);
> +
> +		mm->ksm_merging_pages = 0;
> +		mm->ksm_rmap_items = 0;
> +		atomic_long_add(nr_ksm_zero_pages, &ksm_zero_pages);
>   		__ksm_enter(mm);
> +	}
>   }
>   
>   static inline int ksm_execve(struct mm_struct *mm)
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by David Hildenbrand 2 weeks, 1 day ago
On 15.09.25 17:03, Donet Tom wrote:
> Currently, the KSM-related counters in `mm_struct`, such as
> `ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
> inherited by the child process during fork. This results in inconsistent
> accounting.
> 
> When a process uses KSM, identical pages are merged and an rmap item is
> created for each merged page. The `ksm_merging_pages` and
> `ksm_rmap_items` counters are updated accordingly. However, after a
> fork, these counters are copied to the child while the corresponding
> rmap items are not. As a result, when the child later triggers an
> unmerge, there are no rmap items present in the child, so the counters
> remain stale, leading to incorrect accounting.
> 
> A similar issue exists with `ksm_zero_pages`, which maintains both a
> global counter and a per-process counter. During fork, the per-process
> counter is inherited by the child, but the global counter is not
> incremented. Since the child also references zero pages, the global
> counter should be updated as well. Otherwise, during zero-page unmerge,
> both the global and per-process counters are decremented, causing the
> global counter to become inconsistent.
> 
> To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
> during fork, and the global ksm_zero_pages counter is updated with the
> per-process ksm_zero_pages value inherited by the child. This ensures
> that KSM statistics remain accurate and reflect the activity of each
> process correctly.
> 
> Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
> Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
> Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
> cc: stable@vger.kernel.org # v6.6
> Signed-off-by: Donet Tom <donettom@linux.ibm.com>
> ---
>   include/linux/ksm.h | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/ksm.h b/include/linux/ksm.h
> index 22e67ca7cba3..067538fc4d58 100644
> --- a/include/linux/ksm.h
> +++ b/include/linux/ksm.h
> @@ -56,8 +56,14 @@ static inline long mm_ksm_zero_pages(struct mm_struct *mm)
>   static inline void ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
>   {
>   	/* Adding mm to ksm is best effort on fork. */
> -	if (mm_flags_test(MMF_VM_MERGEABLE, oldmm))
> +	if (mm_flags_test(MMF_VM_MERGEABLE, oldmm)) {
> +		long nr_ksm_zero_pages = atomic_long_read(&mm->ksm_zero_pages);
> +
> +		mm->ksm_merging_pages = 0;
> +		mm->ksm_rmap_items = 0;
> +		atomic_long_add(nr_ksm_zero_pages, &ksm_zero_pages);
>   		__ksm_enter(mm);

That LGTM. KSM is all weird in combination with fork(), but that's 
something for another day to improve I guess.

Acked-by: David Hildenbrand <david@redhat.com>

-- 
Cheers

David / dhildenb
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Andrew Morton 2 weeks, 2 days ago
On Mon, 15 Sep 2025 20:33:04 +0530 Donet Tom <donettom@linux.ibm.com> wrote:

> Currently, the KSM-related counters in `mm_struct`, such as
> `ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
> inherited by the child process during fork. This results in inconsistent
> accounting.
> 
> When a process uses KSM, identical pages are merged and an rmap item is
> created for each merged page. The `ksm_merging_pages` and
> `ksm_rmap_items` counters are updated accordingly. However, after a
> fork, these counters are copied to the child while the corresponding
> rmap items are not. As a result, when the child later triggers an
> unmerge, there are no rmap items present in the child, so the counters
> remain stale, leading to incorrect accounting.
> 
> A similar issue exists with `ksm_zero_pages`, which maintains both a
> global counter and a per-process counter. During fork, the per-process
> counter is inherited by the child, but the global counter is not
> incremented. Since the child also references zero pages, the global
> counter should be updated as well. Otherwise, during zero-page unmerge,
> both the global and per-process counters are decremented, causing the
> global counter to become inconsistent.
> 
> To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
> during fork, and the global ksm_zero_pages counter is updated with the
> per-process ksm_zero_pages value inherited by the child. This ensures
> that KSM statistics remain accurate and reflect the activity of each
> process correctly.
> 
> Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")

Linux-v5.19

> Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")

Linux-v6.1

> Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")

Linux-v6.10

> cc: stable@vger.kernel.org # v6.6

So how was Linux-v6.6 arrived at?

I think the most important use for Fixes: is to tell the -stable
maintainers which kernel version(s) we believe should receive the
patch.  So listing multiple Fixes: targets just causes confusion.

Maybe the -stable maintainers parse the "# v6.6" thing, I don't know. 
But providing them with a single Fixes: recommendation is a good thing
either way.

So can you please revisit this and suggest a single Fixes: target which
clarifies your reccomendation?

Thanks.

(Cc Joe.  Should checkpatch say something about this)?
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Sasha Levin 2 weeks, 2 days ago
On Mon, Sep 15, 2025 at 04:42:48PM -0700, Andrew Morton wrote:
>On Mon, 15 Sep 2025 20:33:04 +0530 Donet Tom <donettom@linux.ibm.com> wrote:
>
>> Currently, the KSM-related counters in `mm_struct`, such as
>> `ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
>> inherited by the child process during fork. This results in inconsistent
>> accounting.
>>
>> When a process uses KSM, identical pages are merged and an rmap item is
>> created for each merged page. The `ksm_merging_pages` and
>> `ksm_rmap_items` counters are updated accordingly. However, after a
>> fork, these counters are copied to the child while the corresponding
>> rmap items are not. As a result, when the child later triggers an
>> unmerge, there are no rmap items present in the child, so the counters
>> remain stale, leading to incorrect accounting.
>>
>> A similar issue exists with `ksm_zero_pages`, which maintains both a
>> global counter and a per-process counter. During fork, the per-process
>> counter is inherited by the child, but the global counter is not
>> incremented. Since the child also references zero pages, the global
>> counter should be updated as well. Otherwise, during zero-page unmerge,
>> both the global and per-process counters are decremented, causing the
>> global counter to become inconsistent.
>>
>> To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
>> during fork, and the global ksm_zero_pages counter is updated with the
>> per-process ksm_zero_pages value inherited by the child. This ensures
>> that KSM statistics remain accurate and reflect the activity of each
>> process correctly.
>>
>> Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
>
>Linux-v5.19
>
>> Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
>
>Linux-v6.1
>
>> Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
>
>Linux-v6.10
>
>> cc: stable@vger.kernel.org # v6.6
>
>So how was Linux-v6.6 arrived at?

e2942062e01d is in v6.6, not in v6.10 - I suspect that this is why the "# v6.6"
part was added.

>I think the most important use for Fixes: is to tell the -stable
>maintainers which kernel version(s) we believe should receive the
>patch.  So listing multiple Fixes: targets just causes confusion.

Right - there's no way of communicating if all the commits listed in multiple
Fixes tags should exist in the tree, or any one of them, for the new fix to be
applicable.

-- 
Thanks,
Sasha
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Donet Tom 2 weeks, 2 days ago
On 9/16/25 10:03 AM, Sasha Levin wrote:
> On Mon, Sep 15, 2025 at 04:42:48PM -0700, Andrew Morton wrote:
>> On Mon, 15 Sep 2025 20:33:04 +0530 Donet Tom <donettom@linux.ibm.com> 
>> wrote:
>>
>>> Currently, the KSM-related counters in `mm_struct`, such as
>>> `ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
>>> inherited by the child process during fork. This results in 
>>> inconsistent
>>> accounting.
>>>
>>> When a process uses KSM, identical pages are merged and an rmap item is
>>> created for each merged page. The `ksm_merging_pages` and
>>> `ksm_rmap_items` counters are updated accordingly. However, after a
>>> fork, these counters are copied to the child while the corresponding
>>> rmap items are not. As a result, when the child later triggers an
>>> unmerge, there are no rmap items present in the child, so the counters
>>> remain stale, leading to incorrect accounting.
>>>
>>> A similar issue exists with `ksm_zero_pages`, which maintains both a
>>> global counter and a per-process counter. During fork, the per-process
>>> counter is inherited by the child, but the global counter is not
>>> incremented. Since the child also references zero pages, the global
>>> counter should be updated as well. Otherwise, during zero-page unmerge,
>>> both the global and per-process counters are decremented, causing the
>>> global counter to become inconsistent.
>>>
>>> To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
>>> during fork, and the global ksm_zero_pages counter is updated with the
>>> per-process ksm_zero_pages value inherited by the child. This ensures
>>> that KSM statistics remain accurate and reflect the activity of each
>>> process correctly.
>>>
>>> Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
>>
>> Linux-v5.19
>>
>>> Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each 
>>> process")
>>
>> Linux-v6.1
>>
>>> Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
>>
>> Linux-v6.10
>>
>>> cc: stable@vger.kernel.org # v6.6
>>
>> So how was Linux-v6.6 arrived at?
>
> e2942062e01d is in v6.6, not in v6.10 - I suspect that this is why the 
> "# v6.6"
> part was added.


Yes, e2942062e01d is in v6.6, which is why I mentioned that we need to 
backport it up to v6.6.


>
>> I think the most important use for Fixes: is to tell the -stable
>> maintainers which kernel version(s) we believe should receive the
>> patch.  So listing multiple Fixes: targets just causes confusion.
>
> Right - there's no way of communicating if all the commits listed in 
> multiple
> Fixes tags should exist in the tree, or any one of them, for the new 
> fix to be
> applicable.
>
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Andrew Morton 2 weeks, 2 days ago
On Tue, 16 Sep 2025 00:33:09 -0400 Sasha Levin <sashal@kernel.org> wrote:

> On Mon, Sep 15, 2025 at 04:42:48PM -0700, Andrew Morton wrote:
> >On Mon, 15 Sep 2025 20:33:04 +0530 Donet Tom <donettom@linux.ibm.com> wrote:
> >
> >> Currently, the KSM-related counters in `mm_struct`, such as
> >> `ksm_merging_pages`, `ksm_rmap_items`, and `ksm_zero_pages`, are
> >> inherited by the child process during fork. This results in inconsistent
> >> accounting.
> >>
> >> When a process uses KSM, identical pages are merged and an rmap item is
> >> created for each merged page. The `ksm_merging_pages` and
> >> `ksm_rmap_items` counters are updated accordingly. However, after a
> >> fork, these counters are copied to the child while the corresponding
> >> rmap items are not. As a result, when the child later triggers an
> >> unmerge, there are no rmap items present in the child, so the counters
> >> remain stale, leading to incorrect accounting.
> >>
> >> A similar issue exists with `ksm_zero_pages`, which maintains both a
> >> global counter and a per-process counter. During fork, the per-process
> >> counter is inherited by the child, but the global counter is not
> >> incremented. Since the child also references zero pages, the global
> >> counter should be updated as well. Otherwise, during zero-page unmerge,
> >> both the global and per-process counters are decremented, causing the
> >> global counter to become inconsistent.
> >>
> >> To fix this, ksm_merging_pages and ksm_rmap_items are reset to 0
> >> during fork, and the global ksm_zero_pages counter is updated with the
> >> per-process ksm_zero_pages value inherited by the child. This ensures
> >> that KSM statistics remain accurate and reflect the activity of each
> >> process correctly.
> >>
> >> Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
> >
> >Linux-v5.19
> >
> >> Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
> >
> >Linux-v6.1
> >
> >> Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
> >
> >Linux-v6.10
> >
> >> cc: stable@vger.kernel.org # v6.6
> >
> >So how was Linux-v6.6 arrived at?
> 
> e2942062e01d is in v6.6, not in v6.10 - I suspect that this is why the "# v6.6"
> part was added.

OK.

> 
> >I think the most important use for Fixes: is to tell the -stable
> >maintainers which kernel version(s) we believe should receive the
> >patch.  So listing multiple Fixes: targets just causes confusion.
> 
> Right - there's no way of communicating if all the commits listed in multiple
> Fixes tags should exist in the tree, or any one of them, for the new fix to be
> applicable.

So what should we do in this situation?
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Sasha Levin 2 weeks, 2 days ago
On Mon, Sep 15, 2025 at 09:41:17PM -0700, Andrew Morton wrote:
>On Tue, 16 Sep 2025 00:33:09 -0400 Sasha Levin <sashal@kernel.org> wrote:
>> On Mon, Sep 15, 2025 at 04:42:48PM -0700, Andrew Morton wrote:
>> >I think the most important use for Fixes: is to tell the -stable
>> >maintainers which kernel version(s) we believe should receive the
>> >patch.  So listing multiple Fixes: targets just causes confusion.
>>
>> Right - there's no way of communicating if all the commits listed in multiple
>> Fixes tags should exist in the tree, or any one of them, for the new fix to be
>> applicable.
>
>So what should we do in this situation?

For us, ideally point to the oldest commit fixed by the new commit with a
Fixes: tag, and then a note along with the stable tag if this is a more complex
scenario that we need to consider.

-- 
Thanks,
Sasha
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Joe Perches 2 weeks, 2 days ago
On Mon, 2025-09-15 at 16:42 -0700, Andrew Morton wrote:
> On Mon, 15 Sep 2025 20:33:04 +0530 Donet Tom <donettom@linux.ibm.com> wrote:
[]
> > Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
> 
> Linux-v5.19
> 
> > Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
> 
> Linux-v6.1
> 
> > Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
> 
> Linux-v6.10
> 
> > cc: stable@vger.kernel.org # v6.6
> 
> So how was Linux-v6.6 arrived at?
[]
> (Cc Joe.  Should checkpatch say something about this)?

Probably not. Parsing variants of versions seems, umm, difficult.
Re: [PATCH v2 1/3] mm/ksm: Fix incorrect KSM counter handling in mm_struct during fork
Posted by Andrew Morton 2 weeks, 2 days ago
On Mon, 15 Sep 2025 19:14:47 -0700 Joe Perches <joe@perches.com> wrote:

> On Mon, 2025-09-15 at 16:42 -0700, Andrew Morton wrote:
> > On Mon, 15 Sep 2025 20:33:04 +0530 Donet Tom <donettom@linux.ibm.com> wrote:
> []
> > > Fixes: 7609385337a4 ("ksm: count ksm merging pages for each process")
> > 
> > Linux-v5.19
> > 
> > > Fixes: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process")
> > 
> > Linux-v6.1
> > 
> > > Fixes: e2942062e01d ("ksm: count all zero pages placed by KSM")
> > 
> > Linux-v6.10
> > 
> > > cc: stable@vger.kernel.org # v6.6
> > 
> > So how was Linux-v6.6 arrived at?
> []
> > (Cc Joe.  Should checkpatch say something about this)?
> 
> Probably not. Parsing variants of versions seems, umm, difficult.

I was thinking simpler.  If the Fixes: count exceeds one, ask
"wtf are you asking of the -stable maintainers"?