diff mbox series

mm: do not update memcg stats for NR_{FILE/SHMEM}_PMDMAPPED

Message ID 20240506170024.202111-1-yosryahmed@google.com (mailing list archive)
State New
Headers show
Series mm: do not update memcg stats for NR_{FILE/SHMEM}_PMDMAPPED | expand

Commit Message

Yosry Ahmed May 6, 2024, 5 p.m. UTC
Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
__mod_node_page_state() instead, which updates the global per-node stats
only.

Reported-by: syzbot+9319a4268a640e26b72b@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/lkml/0000000000001b9d500617c8b23c@google.com
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
 mm/rmap.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

Comments

Yosry Ahmed May 6, 2024, 5:01 p.m. UTC | #1
On Mon, May 6, 2024 at 10:00 AM Yosry Ahmed <yosryahmed@google.com> wrote:
>
> Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
> NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
> __mod_node_page_state() instead, which updates the global per-node stats
> only.
>
> Reported-by: syzbot+9319a4268a640e26b72b@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/lkml/0000000000001b9d500617c8b23c@google.com
> Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
> ---
>  mm/rmap.c | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/mm/rmap.c b/mm/rmap.c
> index 12be4241474ab..c2cfb750d2535 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -1435,13 +1435,14 @@ static __always_inline void __folio_add_file_rmap(struct folio *folio,
>                 struct page *page, int nr_pages, struct vm_area_struct *vma,
>                 enum rmap_level level)
>  {
> +       pg_data_t *pgdat = folio_pgdat(folio);
>         int nr, nr_pmdmapped = 0;
>
>         VM_WARN_ON_FOLIO(folio_test_anon(folio), folio);
>
>         nr = __folio_add_rmap(folio, page, nr_pages, level, &nr_pmdmapped);
>         if (nr_pmdmapped)
> -               __lruvec_stat_mod_folio(folio, folio_test_swapbacked(folio) ?
> +               __mod_node_page_state(pgdat, folio_test_swapbacked(folio) ?
>                         NR_SHMEM_PMDMAPPED : NR_FILE_PMDMAPPED, nr_pmdmapped);
>         if (nr)
>                 __lruvec_stat_mod_folio(folio, NR_FILE_MAPPED, nr);
> @@ -1493,6 +1494,7 @@ static __always_inline void __folio_remove_rmap(struct folio *folio,
>                 enum rmap_level level)
>  {
>         atomic_t *mapped = &folio->_nr_pages_mapped;
> +       pg_data_t *pgdat = folio_pgdat(folio);
>         int last, nr = 0, nr_pmdmapped = 0;
>         bool partially_mapped = false;
>         enum node_stat_item idx;
> @@ -1540,13 +1542,14 @@ static __always_inline void __folio_remove_rmap(struct folio *folio,
>         }
>
>         if (nr_pmdmapped) {
> +               /* NR_{FILE/SHMEM}_PMDMAPPED are not maintained per-memcg */
>                 if (folio_test_anon(folio))
> -                       idx = NR_ANON_THPS;
> -               else if (folio_test_swapbacked(folio))
> -                       idx = NR_SHMEM_PMDMAPPED;
> +                       __lruvec_stat_mod_folio(folio, NR_ANON_THPS, -nr_pmdmapped);
>                 else
> -                       idx = NR_FILE_PMDMAPPED;
> -               __lruvec_stat_mod_folio(folio, idx, -nr_pmdmapped);
> +                       __mod_node_page_state(pgdat,
> +                                       folio_test_swapbacked(folio) ?
> +                                       NR_SHMEM_PMDMAPPED : NR_FILE_PMDMAPPED,
> +                                       nr_pmdmapped);

..and of course right after I press send I realized this should be
-nr_pmdmapped.

>         }
>         if (nr) {
>                 idx = folio_test_anon(folio) ? NR_ANON_MAPPED : NR_FILE_MAPPED;
> --
> 2.45.0.rc1.225.g2a3ae87e7f-goog
>
David Hildenbrand May 6, 2024, 6:35 p.m. UTC | #2
On 06.05.24 19:00, Yosry Ahmed wrote:
> Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
> NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
> __mod_node_page_state() instead, which updates the global per-node stats
> only.

What's the effect of this? IIUC, it's been that way forever, no?

Fixes: ?

Do we want to CC stable?
Yosry Ahmed May 6, 2024, 6:52 p.m. UTC | #3
On Mon, May 6, 2024 at 11:35 AM David Hildenbrand <david@redhat.com> wrote:
>
> On 06.05.24 19:00, Yosry Ahmed wrote:
> > Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
> > NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
> > __mod_node_page_state() instead, which updates the global per-node stats
> > only.
>
> What's the effect of this? IIUC, it's been that way forever, no?

Yes, but it has been the case that all the NR_VM_EVENT_ITEMS stats
were maintained per-memcg, although some of those fields are not
exposed anywhere.

Shakeel recently added commit14e0f6c957e39 ("memcg: reduce memory for
the lruvec and memcg stats"), which changed this such that we only
maintain the stats we actually expose per-memcg (via a translation
table).

He also added commit 514462bbe927b ("memcg: warn for unexpected events
and stats"), which warns if we try to update a stat per-memcg that we
do not maintain per-memcg (i.e. the warning firing here). The goal is
to make sure the translation table has all the stats it needs to have.

Both of these commits were just merged today into mm-stable, hence the
need for the fix now. It is the warning working as intended. No Fixes
or CC stable are needed, but if necessary I would think:

Fixes: 514462bbe927b ("memcg: warn for unexpected events and stats")

, because without the warning, the stat update will just be ignored.
So if anything the warning should have been added *after* this was
fixed up.

>
> Fixes: ?
>
> Do we want to CC stable?
>
>
> --
> Cheers,
>
> David / dhildenb
>
David Hildenbrand May 6, 2024, 7:18 p.m. UTC | #4
On 06.05.24 20:52, Yosry Ahmed wrote:
> On Mon, May 6, 2024 at 11:35 AM David Hildenbrand <david@redhat.com> wrote:
>>
>> On 06.05.24 19:00, Yosry Ahmed wrote:
>>> Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
>>> NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
>>> __mod_node_page_state() instead, which updates the global per-node stats
>>> only.
>>
>> What's the effect of this? IIUC, it's been that way forever, no?
> 
> Yes, but it has been the case that all the NR_VM_EVENT_ITEMS stats
> were maintained per-memcg, although some of those fields are not
> exposed anywhere.
> 
> Shakeel recently added commit14e0f6c957e39 ("memcg: reduce memory for
> the lruvec and memcg stats"), which changed this such that we only
> maintain the stats we actually expose per-memcg (via a translation
> table).

Valuable information we should add to the patch description :)

> 
> He also added commit 514462bbe927b ("memcg: warn for unexpected events
> and stats"), which warns if we try to update a stat per-memcg that we
> do not maintain per-memcg (i.e. the warning firing here). The goal is
> to make sure the translation table has all the stats it needs to have.
> 
> Both of these commits were just merged today into mm-stable, hence the
> need for the fix now. It is the warning working as intended. No Fixes
> or CC stable are needed, but if necessary I would think:

WARN* should usually be "Fixes:"d, because WARN* expresses a condition 
that shouldn't be happening.

Documentation/process/coding-style.rst contains details.

> 
> Fixes: 514462bbe927b ("memcg: warn for unexpected events and stats")
> 
> , because without the warning, the stat update will just be ignored.
> So if anything the warning should have been added *after* this was
> fixed up.

Ideally, yes. But if it's in mm-stable, we usually can no longer 
reshuffle patches (commit IDs stable).
Yosry Ahmed May 6, 2024, 7:22 p.m. UTC | #5
On Mon, May 6, 2024 at 12:18 PM David Hildenbrand <david@redhat.com> wrote:
>
> On 06.05.24 20:52, Yosry Ahmed wrote:
> > On Mon, May 6, 2024 at 11:35 AM David Hildenbrand <david@redhat.com> wrote:
> >>
> >> On 06.05.24 19:00, Yosry Ahmed wrote:
> >>> Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
> >>> NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
> >>> __mod_node_page_state() instead, which updates the global per-node stats
> >>> only.
> >>
> >> What's the effect of this? IIUC, it's been that way forever, no?
> >
> > Yes, but it has been the case that all the NR_VM_EVENT_ITEMS stats
> > were maintained per-memcg, although some of those fields are not
> > exposed anywhere.
> >
> > Shakeel recently added commit14e0f6c957e39 ("memcg: reduce memory for
> > the lruvec and memcg stats"), which changed this such that we only
> > maintain the stats we actually expose per-memcg (via a translation
> > table).
>
> Valuable information we should add to the patch description :)
>
> >
> > He also added commit 514462bbe927b ("memcg: warn for unexpected events
> > and stats"), which warns if we try to update a stat per-memcg that we
> > do not maintain per-memcg (i.e. the warning firing here). The goal is
> > to make sure the translation table has all the stats it needs to have.
> >
> > Both of these commits were just merged today into mm-stable, hence the
> > need for the fix now. It is the warning working as intended. No Fixes
> > or CC stable are needed, but if necessary I would think:
>
> WARN* should usually be "Fixes:"d, because WARN* expresses a condition
> that shouldn't be happening.
>
> Documentation/process/coding-style.rst contains details.
>
> >
> > Fixes: 514462bbe927b ("memcg: warn for unexpected events and stats")
> >
> > , because without the warning, the stat update will just be ignored.
> > So if anything the warning should have been added *after* this was
> > fixed up.
>
> Ideally, yes. But if it's in mm-stable, we usually can no longer
> reshuffle patches (commit IDs stable).

I will send v2 shortly with the missing negative sign, amended commit
log, and the Fixes tag.

Thanks for taking a look!


> --
> Cheers,
>
> David / dhildenb
>
>
Shakeel Butt May 6, 2024, 7:25 p.m. UTC | #6
On Mon, May 06, 2024 at 05:00:24PM +0000, Yosry Ahmed wrote:
> Do not use __lruvec_stat_mod_folio() when updating NR_FILE_PMDMAPPED and
> NR_SHMEM_PMDMAPPED as these stats are not maintained per-memcg. Use
> __mod_node_page_state() instead, which updates the global per-node stats
> only.
> 
> Reported-by: syzbot+9319a4268a640e26b72b@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/lkml/0000000000001b9d500617c8b23c@google.com
> Signed-off-by: Yosry Ahmed <yosryahmed@google.com>

I think we can put Fixes either for 443c077dc2ec ("memcg: cleanup
__mod_memcg_lruvec_state") or ad86c0f0e089 ("memcg: warn for unexpected
events and stats").

> ---
>  mm/rmap.c | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/mm/rmap.c b/mm/rmap.c
> index 12be4241474ab..c2cfb750d2535 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -1435,13 +1435,14 @@ static __always_inline void __folio_add_file_rmap(struct folio *folio,
>  		struct page *page, int nr_pages, struct vm_area_struct *vma,
>  		enum rmap_level level)
>  {
> +	pg_data_t *pgdat = folio_pgdat(folio);
>  	int nr, nr_pmdmapped = 0;
>  
>  	VM_WARN_ON_FOLIO(folio_test_anon(folio), folio);
>  
>  	nr = __folio_add_rmap(folio, page, nr_pages, level, &nr_pmdmapped);
>  	if (nr_pmdmapped)
> -		__lruvec_stat_mod_folio(folio, folio_test_swapbacked(folio) ?
> +		__mod_node_page_state(pgdat, folio_test_swapbacked(folio) ?
>  			NR_SHMEM_PMDMAPPED : NR_FILE_PMDMAPPED, nr_pmdmapped);
>  	if (nr)
>  		__lruvec_stat_mod_folio(folio, NR_FILE_MAPPED, nr);
> @@ -1493,6 +1494,7 @@ static __always_inline void __folio_remove_rmap(struct folio *folio,
>  		enum rmap_level level)
>  {
>  	atomic_t *mapped = &folio->_nr_pages_mapped;
> +	pg_data_t *pgdat = folio_pgdat(folio);
>  	int last, nr = 0, nr_pmdmapped = 0;
>  	bool partially_mapped = false;
>  	enum node_stat_item idx;
> @@ -1540,13 +1542,14 @@ static __always_inline void __folio_remove_rmap(struct folio *folio,
>  	}
>  
>  	if (nr_pmdmapped) {
> +		/* NR_{FILE/SHMEM}_PMDMAPPED are not maintained per-memcg */
>  		if (folio_test_anon(folio))
> -			idx = NR_ANON_THPS;
> -		else if (folio_test_swapbacked(folio))
> -			idx = NR_SHMEM_PMDMAPPED;
> +			__lruvec_stat_mod_folio(folio, NR_ANON_THPS, -nr_pmdmapped);
>  		else
> -			idx = NR_FILE_PMDMAPPED;
> -		__lruvec_stat_mod_folio(folio, idx, -nr_pmdmapped);
> +			__mod_node_page_state(pgdat,
> +					folio_test_swapbacked(folio) ?
> +					NR_SHMEM_PMDMAPPED : NR_FILE_PMDMAPPED,
> +					nr_pmdmapped);

After the above fixed, you can add:

Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
diff mbox series

Patch

diff --git a/mm/rmap.c b/mm/rmap.c
index 12be4241474ab..c2cfb750d2535 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1435,13 +1435,14 @@  static __always_inline void __folio_add_file_rmap(struct folio *folio,
 		struct page *page, int nr_pages, struct vm_area_struct *vma,
 		enum rmap_level level)
 {
+	pg_data_t *pgdat = folio_pgdat(folio);
 	int nr, nr_pmdmapped = 0;
 
 	VM_WARN_ON_FOLIO(folio_test_anon(folio), folio);
 
 	nr = __folio_add_rmap(folio, page, nr_pages, level, &nr_pmdmapped);
 	if (nr_pmdmapped)
-		__lruvec_stat_mod_folio(folio, folio_test_swapbacked(folio) ?
+		__mod_node_page_state(pgdat, folio_test_swapbacked(folio) ?
 			NR_SHMEM_PMDMAPPED : NR_FILE_PMDMAPPED, nr_pmdmapped);
 	if (nr)
 		__lruvec_stat_mod_folio(folio, NR_FILE_MAPPED, nr);
@@ -1493,6 +1494,7 @@  static __always_inline void __folio_remove_rmap(struct folio *folio,
 		enum rmap_level level)
 {
 	atomic_t *mapped = &folio->_nr_pages_mapped;
+	pg_data_t *pgdat = folio_pgdat(folio);
 	int last, nr = 0, nr_pmdmapped = 0;
 	bool partially_mapped = false;
 	enum node_stat_item idx;
@@ -1540,13 +1542,14 @@  static __always_inline void __folio_remove_rmap(struct folio *folio,
 	}
 
 	if (nr_pmdmapped) {
+		/* NR_{FILE/SHMEM}_PMDMAPPED are not maintained per-memcg */
 		if (folio_test_anon(folio))
-			idx = NR_ANON_THPS;
-		else if (folio_test_swapbacked(folio))
-			idx = NR_SHMEM_PMDMAPPED;
+			__lruvec_stat_mod_folio(folio, NR_ANON_THPS, -nr_pmdmapped);
 		else
-			idx = NR_FILE_PMDMAPPED;
-		__lruvec_stat_mod_folio(folio, idx, -nr_pmdmapped);
+			__mod_node_page_state(pgdat,
+					folio_test_swapbacked(folio) ?
+					NR_SHMEM_PMDMAPPED : NR_FILE_PMDMAPPED,
+					nr_pmdmapped);
 	}
 	if (nr) {
 		idx = folio_test_anon(folio) ? NR_ANON_MAPPED : NR_FILE_MAPPED;