diff mbox series

[06/16] mm/page_alloc: fix freeing static percpu memory

Message ID 20220909092451.24883-7-linmiaohe@huawei.com (mailing list archive)
State New
Headers show
Series A few cleanup patches for mm | expand

Commit Message

Miaohe Lin Sept. 9, 2022, 9:24 a.m. UTC
The size of struct per_cpu_zonestat can be 0 on !SMP && !NUMA. In that
case, zone->per_cpu_zonestats will always equal to boot_zonestats. But
in zone_pcp_reset(), zone->per_cpu_zonestats is freed via free_percpu()
directly without checking against boot_zonestats first. boot_zonestats
will be released by free_percpu() unexpectedly.

Fixes: 28f836b6777b ("mm/page_alloc: split per cpu page lists and zone stats")
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
---
 mm/page_alloc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Comments

David Hildenbrand Sept. 9, 2022, 11:28 a.m. UTC | #1
On 09.09.22 11:24, Miaohe Lin wrote:
> The size of struct per_cpu_zonestat can be 0 on !SMP && !NUMA. In that
> case, zone->per_cpu_zonestats will always equal to boot_zonestats. But
> in zone_pcp_reset(), zone->per_cpu_zonestats is freed via free_percpu()
> directly without checking against boot_zonestats first. boot_zonestats
> will be released by free_percpu() unexpectedly.
> 
> Fixes: 28f836b6777b ("mm/page_alloc: split per cpu page lists and zone stats")
> Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
> ---
>   mm/page_alloc.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 3497919f4ef5..a35ef385d906 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -9510,9 +9510,11 @@ void zone_pcp_reset(struct zone *zone)
>   			drain_zonestat(zone, pzstats);
>   		}
>   		free_percpu(zone->per_cpu_pageset);
> -		free_percpu(zone->per_cpu_zonestats);
>   		zone->per_cpu_pageset = &boot_pageset;
> -		zone->per_cpu_zonestats = &boot_zonestats;
> +		if (zone->per_cpu_zonestats != &boot_zonestats) {
> +			free_percpu(zone->per_cpu_zonestats);
> +			zone->per_cpu_zonestats = &boot_zonestats;
> +		}
>   	}
>   }
>   

Reviewed-by: David Hildenbrand <david@redhat.com>
Oscar Salvador Sept. 15, 2022, 4:53 a.m. UTC | #2
On Fri, Sep 09, 2022 at 05:24:41PM +0800, Miaohe Lin wrote:
> The size of struct per_cpu_zonestat can be 0 on !SMP && !NUMA. In that
> case, zone->per_cpu_zonestats will always equal to boot_zonestats. But
> in zone_pcp_reset(), zone->per_cpu_zonestats is freed via free_percpu()
> directly without checking against boot_zonestats first. boot_zonestats
> will be released by free_percpu() unexpectedly.
> 
> Fixes: 28f836b6777b ("mm/page_alloc: split per cpu page lists and zone stats")
> Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>

Reviewed-by: Oscar Salvador <osalvador@suse.de>
diff mbox series

Patch

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3497919f4ef5..a35ef385d906 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -9510,9 +9510,11 @@  void zone_pcp_reset(struct zone *zone)
 			drain_zonestat(zone, pzstats);
 		}
 		free_percpu(zone->per_cpu_pageset);
-		free_percpu(zone->per_cpu_zonestats);
 		zone->per_cpu_pageset = &boot_pageset;
-		zone->per_cpu_zonestats = &boot_zonestats;
+		if (zone->per_cpu_zonestats != &boot_zonestats) {
+			free_percpu(zone->per_cpu_zonestats);
+			zone->per_cpu_zonestats = &boot_zonestats;
+		}
 	}
 }