linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem
@ 2016-11-01 13:59 James Hogan
  2016-11-01 13:59 ` James Hogan
  2016-11-01 19:50 ` Florian Fainelli
  0 siblings, 2 replies; 5+ messages in thread
From: James Hogan @ 2016-11-01 13:59 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: James Hogan, Paul Burton, linux-mips

When low memory doesn't reach HIGHMEM_START (e.g. up to 256MB at PA=0 is
common) and highmem is present above HIGHMEM_START (e.g. on Malta the
RAM overlayed by the IO region is aliased at PA=0x90000000), max_low_pfn
will be initially calculated very large and then clipped down to
HIGHMEM_START.

This causes crashes when reading /sys/kernel/mm/page_idle/bitmap
(i.e. CONFIG_IDLE_PAGE_TRACKING=y) when highmem is disabled. pfn_valid()
will compare against max_mapnr which is derived from max_low_pfn when
there is no highend_pfn set up, and will return true for PFNs right up
to HIGHMEM_START, even though they are beyond the end of low memory and
no page structs will actually exist for these PFNs.

This is fixed by skipping high memory regions when initially calculating
max_low_pfn if highmem is disabled, so it doesn't get clipped too high.
We also clip regions which overlap the highmem boundary when highmem is
disabled, so that max_pfn doesn't extend into highmem either.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
---
 arch/mips/kernel/setup.c | 13 +++++++++++++
 1 file changed, 13 insertions(+), 0 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 0d57909d9026..f66e5ce505b2 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -368,6 +368,19 @@ static void __init bootmem_init(void)
 		end = PFN_DOWN(boot_mem_map.map[i].addr
 				+ boot_mem_map.map[i].size);
 
+#ifndef CONFIG_HIGHMEM
+		/*
+		 * Skip highmem here so we get an accurate max_low_pfn if low
+		 * memory stops short of high memory.
+		 * If the region overlaps HIGHMEM_START, end is clipped so
+		 * max_pfn excludes the highmem portion.
+		 */
+		if (start >= PFN_DOWN(HIGHMEM_START))
+			continue;
+		if (end > PFN_DOWN(HIGHMEM_START))
+			end = PFN_DOWN(HIGHMEM_START);
+#endif
+
 		if (end > max_low_pfn)
 			max_low_pfn = end;
 		if (start < min_low_pfn)
-- 
git-series 0.8.10

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

* [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem
  2016-11-01 13:59 [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem James Hogan
@ 2016-11-01 13:59 ` James Hogan
  2016-11-01 19:50 ` Florian Fainelli
  1 sibling, 0 replies; 5+ messages in thread
From: James Hogan @ 2016-11-01 13:59 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: James Hogan, Paul Burton, linux-mips

When low memory doesn't reach HIGHMEM_START (e.g. up to 256MB at PA=0 is
common) and highmem is present above HIGHMEM_START (e.g. on Malta the
RAM overlayed by the IO region is aliased at PA=0x90000000), max_low_pfn
will be initially calculated very large and then clipped down to
HIGHMEM_START.

This causes crashes when reading /sys/kernel/mm/page_idle/bitmap
(i.e. CONFIG_IDLE_PAGE_TRACKING=y) when highmem is disabled. pfn_valid()
will compare against max_mapnr which is derived from max_low_pfn when
there is no highend_pfn set up, and will return true for PFNs right up
to HIGHMEM_START, even though they are beyond the end of low memory and
no page structs will actually exist for these PFNs.

This is fixed by skipping high memory regions when initially calculating
max_low_pfn if highmem is disabled, so it doesn't get clipped too high.
We also clip regions which overlap the highmem boundary when highmem is
disabled, so that max_pfn doesn't extend into highmem either.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
---
 arch/mips/kernel/setup.c | 13 +++++++++++++
 1 file changed, 13 insertions(+), 0 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 0d57909d9026..f66e5ce505b2 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -368,6 +368,19 @@ static void __init bootmem_init(void)
 		end = PFN_DOWN(boot_mem_map.map[i].addr
 				+ boot_mem_map.map[i].size);
 
+#ifndef CONFIG_HIGHMEM
+		/*
+		 * Skip highmem here so we get an accurate max_low_pfn if low
+		 * memory stops short of high memory.
+		 * If the region overlaps HIGHMEM_START, end is clipped so
+		 * max_pfn excludes the highmem portion.
+		 */
+		if (start >= PFN_DOWN(HIGHMEM_START))
+			continue;
+		if (end > PFN_DOWN(HIGHMEM_START))
+			end = PFN_DOWN(HIGHMEM_START);
+#endif
+
 		if (end > max_low_pfn)
 			max_low_pfn = end;
 		if (start < min_low_pfn)
-- 
git-series 0.8.10

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

* Re: [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem
  2016-11-01 13:59 [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem James Hogan
  2016-11-01 13:59 ` James Hogan
@ 2016-11-01 19:50 ` Florian Fainelli
  2016-11-01 20:53   ` James Hogan
  1 sibling, 1 reply; 5+ messages in thread
From: Florian Fainelli @ 2016-11-01 19:50 UTC (permalink / raw)
  To: James Hogan, Ralf Baechle; +Cc: Paul Burton, linux-mips

On 11/01/2016 06:59 AM, James Hogan wrote:
> When low memory doesn't reach HIGHMEM_START (e.g. up to 256MB at PA=0 is
> common) and highmem is present above HIGHMEM_START (e.g. on Malta the
> RAM overlayed by the IO region is aliased at PA=0x90000000), max_low_pfn
> will be initially calculated very large and then clipped down to
> HIGHMEM_START.
> 
> This causes crashes when reading /sys/kernel/mm/page_idle/bitmap
> (i.e. CONFIG_IDLE_PAGE_TRACKING=y) when highmem is disabled. pfn_valid()
> will compare against max_mapnr which is derived from max_low_pfn when
> there is no highend_pfn set up, and will return true for PFNs right up
> to HIGHMEM_START, even though they are beyond the end of low memory and
> no page structs will actually exist for these PFNs.
> 
> This is fixed by skipping high memory regions when initially calculating
> max_low_pfn if highmem is disabled, so it doesn't get clipped too high.
> We also clip regions which overlap the highmem boundary when highmem is
> disabled, so that max_pfn doesn't extend into highmem either.
> 
> Signed-off-by: James Hogan <james.hogan@imgtec.com>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Paul Burton <paul.burton@imgtec.com>
> Cc: linux-mips@linux-mips.org

Should this also go to -stable, if so, which kernels would be affected?
-- 
Florian

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

* Re: [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem
  2016-11-01 19:50 ` Florian Fainelli
@ 2016-11-01 20:53   ` James Hogan
  2016-11-01 20:53     ` James Hogan
  0 siblings, 1 reply; 5+ messages in thread
From: James Hogan @ 2016-11-01 20:53 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: Ralf Baechle, Paul Burton, linux-mips

[-- Attachment #1: Type: text/plain, Size: 2701 bytes --]

On Tue, Nov 01, 2016 at 12:50:51PM -0700, Florian Fainelli wrote:
> On 11/01/2016 06:59 AM, James Hogan wrote:
> > When low memory doesn't reach HIGHMEM_START (e.g. up to 256MB at PA=0 is
> > common) and highmem is present above HIGHMEM_START (e.g. on Malta the
> > RAM overlayed by the IO region is aliased at PA=0x90000000), max_low_pfn
> > will be initially calculated very large and then clipped down to
> > HIGHMEM_START.
> > 
> > This causes crashes when reading /sys/kernel/mm/page_idle/bitmap
> > (i.e. CONFIG_IDLE_PAGE_TRACKING=y) when highmem is disabled. pfn_valid()
> > will compare against max_mapnr which is derived from max_low_pfn when
> > there is no highend_pfn set up, and will return true for PFNs right up
> > to HIGHMEM_START, even though they are beyond the end of low memory and
> > no page structs will actually exist for these PFNs.
> > 
> > This is fixed by skipping high memory regions when initially calculating
> > max_low_pfn if highmem is disabled, so it doesn't get clipped too high.
> > We also clip regions which overlap the highmem boundary when highmem is
> > disabled, so that max_pfn doesn't extend into highmem either.
> > 
> > Signed-off-by: James Hogan <james.hogan@imgtec.com>
> > Cc: Ralf Baechle <ralf@linux-mips.org>
> > Cc: Paul Burton <paul.burton@imgtec.com>
> > Cc: linux-mips@linux-mips.org
> 
> Should this also go to -stable, if so, which kernels would be affected?

Well idle page tracking is quite a recent addition, commit 33c3fc71c8cf
("mm: introduce idle page tracking") in v4.3, but there could be other
places where pfns are walked with pfn_valid() where this problem could
break things.

But the actual code setting up max_low_pfn hasn't handled this case
properly since it was added in commit db84dc61552a ("[MIPS] Setup
min_low_pfn/max_low_pfn correctly") in v2.6.21.

At least for Malta where I saw it on QEMU however it doesn't appear
(from brief digging in history) to read ememsize environment except for
EVA kernels, except possibly since v4.4 with the new dtshim or a newish
u-boot capable of passing RAM size via DT.

So since I wasn't sure whether it really affects anybody else, and how
important it is to them, nor how far back it really matters (I was only
playing with idle page tracking since it hits the KVM_CAP_SYNC_MMU
related KVM arch callbacks), I figured I'd play it by ear. Thoughts
welcome.

Reproducing is simply a case of a 32bit kernel with CONFIG_HIGHMEM=n,
CONFIG_IDLE_PAGE_TRACKING=y, a platform that reports high memory regions
but with < 512MB of lowmem, then this to see if you get a kernel splat:

hexdump /sys/kernel/mm/page_idle/bitmap

Cheers
James

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem
  2016-11-01 20:53   ` James Hogan
@ 2016-11-01 20:53     ` James Hogan
  0 siblings, 0 replies; 5+ messages in thread
From: James Hogan @ 2016-11-01 20:53 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: Ralf Baechle, Paul Burton, linux-mips

[-- Attachment #1: Type: text/plain, Size: 2701 bytes --]

On Tue, Nov 01, 2016 at 12:50:51PM -0700, Florian Fainelli wrote:
> On 11/01/2016 06:59 AM, James Hogan wrote:
> > When low memory doesn't reach HIGHMEM_START (e.g. up to 256MB at PA=0 is
> > common) and highmem is present above HIGHMEM_START (e.g. on Malta the
> > RAM overlayed by the IO region is aliased at PA=0x90000000), max_low_pfn
> > will be initially calculated very large and then clipped down to
> > HIGHMEM_START.
> > 
> > This causes crashes when reading /sys/kernel/mm/page_idle/bitmap
> > (i.e. CONFIG_IDLE_PAGE_TRACKING=y) when highmem is disabled. pfn_valid()
> > will compare against max_mapnr which is derived from max_low_pfn when
> > there is no highend_pfn set up, and will return true for PFNs right up
> > to HIGHMEM_START, even though they are beyond the end of low memory and
> > no page structs will actually exist for these PFNs.
> > 
> > This is fixed by skipping high memory regions when initially calculating
> > max_low_pfn if highmem is disabled, so it doesn't get clipped too high.
> > We also clip regions which overlap the highmem boundary when highmem is
> > disabled, so that max_pfn doesn't extend into highmem either.
> > 
> > Signed-off-by: James Hogan <james.hogan@imgtec.com>
> > Cc: Ralf Baechle <ralf@linux-mips.org>
> > Cc: Paul Burton <paul.burton@imgtec.com>
> > Cc: linux-mips@linux-mips.org
> 
> Should this also go to -stable, if so, which kernels would be affected?

Well idle page tracking is quite a recent addition, commit 33c3fc71c8cf
("mm: introduce idle page tracking") in v4.3, but there could be other
places where pfns are walked with pfn_valid() where this problem could
break things.

But the actual code setting up max_low_pfn hasn't handled this case
properly since it was added in commit db84dc61552a ("[MIPS] Setup
min_low_pfn/max_low_pfn correctly") in v2.6.21.

At least for Malta where I saw it on QEMU however it doesn't appear
(from brief digging in history) to read ememsize environment except for
EVA kernels, except possibly since v4.4 with the new dtshim or a newish
u-boot capable of passing RAM size via DT.

So since I wasn't sure whether it really affects anybody else, and how
important it is to them, nor how far back it really matters (I was only
playing with idle page tracking since it hits the KVM_CAP_SYNC_MMU
related KVM arch callbacks), I figured I'd play it by ear. Thoughts
welcome.

Reproducing is simply a case of a 32bit kernel with CONFIG_HIGHMEM=n,
CONFIG_IDLE_PAGE_TRACKING=y, a platform that reports high memory regions
but with < 512MB of lowmem, then this to see if you get a kernel splat:

hexdump /sys/kernel/mm/page_idle/bitmap

Cheers
James

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

end of thread, other threads:[~2016-11-01 20:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-01 13:59 [PATCH v2] MIPS: Fix max_low_pfn with disabled highmem James Hogan
2016-11-01 13:59 ` James Hogan
2016-11-01 19:50 ` Florian Fainelli
2016-11-01 20:53   ` James Hogan
2016-11-01 20:53     ` James Hogan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).