Skip to contentSkip to conversation

mm, page_alloc: Fix a division by zero error when boosting watermarks

PATCH In review Mel Gorman 3 participants 6 messages Feb 13, 2019

Subsystems (2)
lore
Share & tools
lore

Mel Gorman

author
#0 lore raw

PATCH 1/1 mm, page_alloc: Fix a division by zero error when boosting watermarks

Yury Norov reported that an arm64 KVM instance could not boot since after v5.0-rc1 and could addressed by reverting the patches

1c30844d2dfe272d58c ("mm: reclaim small amounts of memory when an external 73444bc4d8f92e46a20 ("mm, page_alloc: do not wake kswapd with zone lock held")

The problem is that a division by zero error is possible if boosting occurs either very early in boot or if the high watermark is very small. This patch checks for the conditions and avoids boosting in those cases.

Fixes 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs")
Reported-and-tested-by Yury Norov <[email protected]>
---
 mm/page_alloc.c | 5 +++++
 1 file changed, 5 insertions(+)
mm/page_alloc.c +5 -0
index d295c9bc01a8..ae7e4ba5b9f5 100644
@@ -2170,6 +2170,11 @@ static inline void boost_watermark(struct zone *zone)
 
 	max_boost = mult_frac(zone->_watermark[WMARK_HIGH],
 			watermark_boost_factor, 10000);
+
+	/* high watermark be be uninitialised or very small */
+	if (!max_boost)
+		return;
+
 	max_boost = max(pageblock_nr_pages, max_boost);
 
 	zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages,
Signature · 2 lines
Mel Gorman
SUSE Labs
Tested-by on v1 1/1
#1 lore raw
Quoted 23 lines · Mel Gorman

Yury Norov reported that an arm64 KVM instance could not boot since after v5.0-rc1 and could addressed by reverting the patches

1c30844d2dfe272d58c ("mm: reclaim small amounts of memory when an external 73444bc4d8f92e46a20 ("mm, page_alloc: do not wake kswapd with zone lock held")

The problem is that a division by zero error is possible if boosting occurs either very early in boot or if the high watermark is very small. This patch checks for the conditions and avoids boosting in those cases.

Fixes 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs")
Reported-and-tested-by Yury Norov <[email protected]>
---
 mm/page_alloc.c | 5 +++++
 1 file changed, 5 insertions(+)
mm/page_alloc.c +0 -0
index d295c9bc01a8..ae7e4ba5b9f5 100644
@@ -2170,6 +2170,11 @@ static inline void boost_watermark(struct zone *zone)
 

mm/page_alloc.c static inline void boost_watermark(struct zone *zone) · line 2180

Quoted 10 lines
mm/page_alloc.c +5 -0
 	max_boost = mult_frac(zone->_watermark[WMARK_HIGH],
 			watermark_boost_factor, 10000);
+
+	/* high watermark be be uninitialised or very small */
+	if (!max_boost)
+		return;
+
 	max_boost = max(pageblock_nr_pages, max_boost);
 
 	zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages,

I can confirm that this also allows my KVM guest to boot:

Will

#2 lore raw
In reply to Mel Gorman
Quoted 9 lines · Mel Gorman

Yury Norov reported that an arm64 KVM instance could not boot since after v5.0-rc1 and could addressed by reverting the patches

1c30844d2dfe272d58c ("mm: reclaim small amounts of memory when an external 73444bc4d8f92e46a20 ("mm, page_alloc: do not wake kswapd with zone lock held")

The problem is that a division by zero error is possible if boosting occurs either very early in boot or if the high watermark is very small. This patch checks for the conditions and avoids boosting in those cases.

Hmm is it really a division by zero? The following line sets max_boost to pageblock_nr_pages if it's zero. And where would the division happen anyway?

So I wonder what's going on, your patch should AFAICS only take effect when zone->_watermark[WMARK_HIGH] is 0 or 1 to begin with, otherwise max_boost is at least 2?

Also upon closer look, I think that (prior to the patch), boost_watermark() could be reduced (thanks to the max+min capping) to

zone->watermark_boost = pageblock_nr_pages

?

Quoted 25 lines
Fixes 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs")
Reported-and-tested-by Yury Norov <[email protected]>
---
 mm/page_alloc.c | 5 +++++
 1 file changed, 5 insertions(+)
mm/page_alloc.c +5 -0
index d295c9bc01a8..ae7e4ba5b9f5 100644
@@ -2170,6 +2170,11 @@ static inline void boost_watermark(struct zone *zone)
 
 	max_boost = mult_frac(zone->_watermark[WMARK_HIGH],
 			watermark_boost_factor, 10000);
+
+	/* high watermark be be uninitialised or very small */
+	if (!max_boost)
+		return;
+
 	max_boost = max(pageblock_nr_pages, max_boost);
 
 	zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages,
author
#3 lore raw
Quoted 11 lines · Vlastimil Babka
Quoted 9 lines · Mel Gorman

Yury Norov reported that an arm64 KVM instance could not boot since after v5.0-rc1 and could addressed by reverting the patches

1c30844d2dfe272d58c ("mm: reclaim small amounts of memory when an external 73444bc4d8f92e46a20 ("mm, page_alloc: do not wake kswapd with zone lock held")

The problem is that a division by zero error is possible if boosting occurs either very early in boot or if the high watermark is very small. This patch checks for the conditions and avoids boosting in those cases.

Quoted 7 lines

Hmm is it really a division by zero? The following line sets max_boost to pageblock_nr_pages if it's zero. And where would the division happen anyway?

So I wonder what's going on, your patch should AFAICS only take effect when zone->_watermark[WMARK_HIGH] is 0 or 1 to begin with, otherwise max_boost is at least 2?

The issue can occur if pageblock_nr_pages is also zero or not yet initialised. It means the changelog is misleading because it has to trigger very early in boot as happened with Yury.

Quoted 5 lines

Also upon closer look, I think that (prior to the patch), boost_watermark() could be reduced (thanks to the max+min capping) to

zone->watermark_boost = pageblock_nr_pages

I don't think it's worth being fancy about it if we're hitting fragmentation issues that early in boot.

Signature · 2 lines
Mel Gorman
SUSE Labs
author
#4 lore raw

PATCH 1/1 mm, page_alloc: Fix a division by zero error when boosting watermarks v2

In reply to Mel Gorman

Yury Norov reported that an arm64 KVM instance could not boot since after v5.0-rc1 and could addressed by reverting the patches

1c30844d2dfe272d58c ("mm: reclaim small amounts of memory when an external 73444bc4d8f92e46a20 ("mm, page_alloc: do not wake kswapd with zone lock held")

The problem is that a division by zero error is possible if boosting occurs very early in boot if the system has very little memory. This patch avoids the division by zero error.

Fixes 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs")
Reported-and-tested-by Yury Norov <[email protected]>
---
 mm/page_alloc.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
mm/page_alloc.c +12 -0
index d295c9bc01a8..bb1c7d843ebf 100644
@@ -2170,6 +2170,18 @@ static inline void boost_watermark(struct zone *zone)
 
 	max_boost = mult_frac(zone->_watermark[WMARK_HIGH],
 			watermark_boost_factor, 10000);
+
+	/*
+	 * high watermark may be uninitialised if fragmentation occurs
+	 * very early in boot so do not boost. We do not fall
+	 * through and boost by pageblock_nr_pages as failing
+	 * allocations that early means that reclaim is not going
+	 * to help and it may even be impossible to reclaim the
+	 * boosted watermark resulting in a hang.
+	 */
+	if (!max_boost)
+		return;
+
 	max_boost = max(pageblock_nr_pages, max_boost);
 
 	zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages,
Signature · 2 lines
Mel Gorman
SUSE Labs
Acked-by on v1 1/1
#5 lore raw

Re: [PATCH] mm, page_alloc: Fix a division by zero error when boosting watermarks v2

Quoted 6 lines · Mel Gorman

Yury Norov reported that an arm64 KVM instance could not boot since after v5.0-rc1 and could addressed by reverting the patches

1c30844d2dfe272d58c ("mm: reclaim small amounts of memory when an external 73444bc4d8f92e46a20 ("mm, page_alloc: do not wake kswapd with zone lock held")

Quoted 8 lines

The problem is that a division by zero error is possible if boosting occurs very early in boot if the system has very little memory. This patch avoids the division by zero error.

Fixes 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs")
Reported-and-tested-by Yury Norov <[email protected]>

Thanks, sorry for the noise before.

Quoted 28 lines
---
 mm/page_alloc.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
mm/page_alloc.c +12 -0
index d295c9bc01a8..bb1c7d843ebf 100644
@@ -2170,6 +2170,18 @@ static inline void boost_watermark(struct zone *zone)
 
 	max_boost = mult_frac(zone->_watermark[WMARK_HIGH],
 			watermark_boost_factor, 10000);
+
+	/*
+	 * high watermark may be uninitialised if fragmentation occurs
+	 * very early in boot so do not boost. We do not fall
+	 * through and boost by pageblock_nr_pages as failing
+	 * allocations that early means that reclaim is not going
+	 * to help and it may even be impossible to reclaim the
+	 * boosted watermark resulting in a hang.
+	 */
+	if (!max_boost)
+		return;
+
 	max_boost = max(pageblock_nr_pages, max_boost);
 
 	zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages,