2021-03-05 05:25:06

by Anshuman Khandual

[permalink] [raw]
Subject: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

This series fixes pfn_valid() for ZONE_DEVICE based memory and also improves
its performance for normal hotplug memory. While here, it also reorganizes
pfn_valid() on CONFIG_SPARSEMEM. This series is based on v5.12-rc1.

Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: James Morse <[email protected]>
Cc: Robin Murphy <[email protected]>
Cc: Jérôme Glisse <[email protected]>
Cc: Dan Williams <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Mike Rapoport <[email protected]>
Cc: Veronika Kabatova <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]

Changes in V3:

- Validate the pfn before fetching mem_section with __pfn_to_section() in [PATCH 2/2]

Changes in V2:

https://lore.kernel.org/linux-mm/[email protected]/

- Dropped pfn_valid() bifurcation based on CONFIG_SPARSEMEM
- Used PFN_PHYS() and PHYS_PFN() instead of __pfn_to_phys() and __phys_to_pfn()
- Moved __pfn_to_section() inside #ifdef CONFIG_SPARSEMEM with a { } construct

Changes in V1:

https://lore.kernel.org/linux-mm/[email protected]/

- Test pfn_section_valid() for non boot memory

Changes in RFC:

https://lore.kernel.org/linux-arm-kernel/[email protected]/

Anshuman Khandual (2):
arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory
arm64/mm: Reorganize pfn_valid()

arch/arm64/mm/init.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)

--
2.20.1


2021-03-05 05:25:14

by Anshuman Khandual

[permalink] [raw]
Subject: [PATCH V3 1/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

pfn_valid() validates a pfn but basically it checks for a valid struct page
backing for that pfn. It should always return positive for memory ranges
backed with struct page mapping. But currently pfn_valid() fails for all
ZONE_DEVICE based memory types even though they have struct page mapping.

pfn_valid() asserts that there is a memblock entry for a given pfn without
MEMBLOCK_NOMAP flag being set. The problem with ZONE_DEVICE based memory is
that they do not have memblock entries. Hence memblock_is_map_memory() will
invariably fail via memblock_search() for a ZONE_DEVICE based address. This
eventually fails pfn_valid() which is wrong. memblock_is_map_memory() needs
to be skipped for such memory ranges. As ZONE_DEVICE memory gets hotplugged
into the system via memremap_pages() called from a driver, their respective
memory sections will not have SECTION_IS_EARLY set.

Normal hotplug memory will never have MEMBLOCK_NOMAP set in their memblock
regions. Because the flag MEMBLOCK_NOMAP was specifically designed and set
for firmware reserved memory regions. memblock_is_map_memory() can just be
skipped as its always going to be positive and that will be an optimization
for the normal hotplug memory. Like ZONE_DEVICE based memory, all normal
hotplugged memory too will not have SECTION_IS_EARLY set for their sections

Skipping memblock_is_map_memory() for all non early memory sections would
fix pfn_valid() problem for ZONE_DEVICE based memory and also improve its
performance for normal hotplug memory as well.

Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Robin Murphy <[email protected]>
Cc: [email protected]
Cc: [email protected]
Acked-by: David Hildenbrand <[email protected]>
Fixes: 73b20c84d42d ("arm64: mm: implement pte_devmap support")
Signed-off-by: Anshuman Khandual <[email protected]>
---
arch/arm64/mm/init.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 0ace5e68efba..5920c527845a 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -230,6 +230,18 @@ int pfn_valid(unsigned long pfn)

if (!valid_section(__pfn_to_section(pfn)))
return 0;
+
+ /*
+ * ZONE_DEVICE memory does not have the memblock entries.
+ * memblock_is_map_memory() check for ZONE_DEVICE based
+ * addresses will always fail. Even the normal hotplugged
+ * memory will never have MEMBLOCK_NOMAP flag set in their
+ * memblock entries. Skip memblock search for all non early
+ * memory sections covering all of hotplug memory including
+ * both normal and ZONE_DEVICE based.
+ */
+ if (!early_section(__pfn_to_section(pfn)))
+ return pfn_section_valid(__pfn_to_section(pfn), pfn);
#endif
return memblock_is_map_memory(addr);
}
--
2.20.1

2021-03-05 05:26:36

by Anshuman Khandual

[permalink] [raw]
Subject: [PATCH V3 2/2] arm64/mm: Reorganize pfn_valid()

There are multiple instances of pfn_to_section_nr() and __pfn_to_section()
when CONFIG_SPARSEMEM is enabled. This can be optimized if memory section
is fetched earlier. This replaces the open coded PFN and ADDR conversion
with PFN_PHYS() and PHYS_PFN() helpers. While there, also add a comment.
This does not cause any functional change.

Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: [email protected]
Cc: [email protected]
Reviewed-by: David Hildenbrand <[email protected]>
Signed-off-by: Anshuman Khandual <[email protected]>
---
arch/arm64/mm/init.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 5920c527845a..3685e12aba9b 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -219,16 +219,26 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)

int pfn_valid(unsigned long pfn)
{
- phys_addr_t addr = pfn << PAGE_SHIFT;
+ phys_addr_t addr = PFN_PHYS(pfn);

- if ((addr >> PAGE_SHIFT) != pfn)
+ /*
+ * Ensure the upper PAGE_SHIFT bits are clear in the
+ * pfn. Else it might lead to false positives when
+ * some of the upper bits are set, but the lower bits
+ * match a valid pfn.
+ */
+ if (PHYS_PFN(addr) != pfn)
return 0;

#ifdef CONFIG_SPARSEMEM
+{
+ struct mem_section *ms;
+
if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
return 0;

- if (!valid_section(__pfn_to_section(pfn)))
+ ms = __pfn_to_section(pfn);
+ if (!valid_section(ms))
return 0;

/*
@@ -240,8 +250,9 @@ int pfn_valid(unsigned long pfn)
* memory sections covering all of hotplug memory including
* both normal and ZONE_DEVICE based.
*/
- if (!early_section(__pfn_to_section(pfn)))
- return pfn_section_valid(__pfn_to_section(pfn), pfn);
+ if (!early_section(ms))
+ return pfn_section_valid(ms, pfn);
+}
#endif
return memblock_is_map_memory(addr);
}
--
2.20.1

2021-03-05 05:38:14

by Anshuman Khandual

[permalink] [raw]
Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory


On 3/5/21 10:54 AM, Anshuman Khandual wrote:
> This series fixes pfn_valid() for ZONE_DEVICE based memory and also improves
> its performance for normal hotplug memory. While here, it also reorganizes
> pfn_valid() on CONFIG_SPARSEMEM. This series is based on v5.12-rc1.
>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Ard Biesheuvel <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: James Morse <[email protected]>
> Cc: Robin Murphy <[email protected]>
> Cc: Jérôme Glisse <[email protected]>
> Cc: Dan Williams <[email protected]>
> Cc: David Hildenbrand <[email protected]>
> Cc: Mike Rapoport <[email protected]>
> Cc: Veronika Kabatova <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
>
> Changes in V3:
>
> - Validate the pfn before fetching mem_section with __pfn_to_section() in [PATCH 2/2]

Hello Veronica,

Could you please help recreate the earlier failure [1] but with this
series applies on v5.12-rc1. Thank you.

[1] https://lore.kernel.org/linux-arm-kernel/[email protected]/

- Anshuman

2021-03-05 12:31:48

by Veronika Kabatova

[permalink] [raw]
Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory



----- Original Message -----
> From: "Anshuman Khandual" <[email protected]>
> To: [email protected], [email protected], [email protected]
> Cc: "Catalin Marinas" <[email protected]>, "Will Deacon" <[email protected]>, "Ard Biesheuvel" <[email protected]>,
> "Mark Rutland" <[email protected]>, "James Morse" <[email protected]>, "Robin Murphy" <[email protected]>,
> "Jérôme Glisse" <[email protected]>, "Dan Williams" <[email protected]>, "David Hildenbrand"
> <[email protected]>, "Mike Rapoport" <[email protected]>, "Veronika Kabatova" <[email protected]>
> Sent: Friday, March 5, 2021 6:38:14 AM
> Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory
>
>
> On 3/5/21 10:54 AM, Anshuman Khandual wrote:
> > This series fixes pfn_valid() for ZONE_DEVICE based memory and also
> > improves
> > its performance for normal hotplug memory. While here, it also reorganizes
> > pfn_valid() on CONFIG_SPARSEMEM. This series is based on v5.12-rc1.
> >
> > Cc: Catalin Marinas <[email protected]>
> > Cc: Will Deacon <[email protected]>
> > Cc: Ard Biesheuvel <[email protected]>
> > Cc: Mark Rutland <[email protected]>
> > Cc: James Morse <[email protected]>
> > Cc: Robin Murphy <[email protected]>
> > Cc: Jérôme Glisse <[email protected]>
> > Cc: Dan Williams <[email protected]>
> > Cc: David Hildenbrand <[email protected]>
> > Cc: Mike Rapoport <[email protected]>
> > Cc: Veronika Kabatova <[email protected]>
> > Cc: [email protected]
> > Cc: [email protected]
> > Cc: [email protected]
> >
> > Changes in V3:
> >
> > - Validate the pfn before fetching mem_section with __pfn_to_section() in
> > [PATCH 2/2]
>
> Hello Veronica,
>
> Could you please help recreate the earlier failure [1] but with this
> series applies on v5.12-rc1. Thank you.
>

Hello Anshuman,

the machine in question is currently loaned to a developer. I'll reach
out to them and will let you know once I have any results.


Veronika

> [1]
> https://lore.kernel.org/linux-arm-kernel/[email protected]/
>
> - Anshuman
>
>

2021-03-05 18:18:25

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH V3 1/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

On Fri, Mar 05, 2021 at 10:54:57AM +0530, Anshuman Khandual wrote:
> pfn_valid() validates a pfn but basically it checks for a valid struct page
> backing for that pfn. It should always return positive for memory ranges
> backed with struct page mapping. But currently pfn_valid() fails for all
> ZONE_DEVICE based memory types even though they have struct page mapping.
>
> pfn_valid() asserts that there is a memblock entry for a given pfn without
> MEMBLOCK_NOMAP flag being set. The problem with ZONE_DEVICE based memory is
> that they do not have memblock entries. Hence memblock_is_map_memory() will
> invariably fail via memblock_search() for a ZONE_DEVICE based address. This
> eventually fails pfn_valid() which is wrong. memblock_is_map_memory() needs
> to be skipped for such memory ranges. As ZONE_DEVICE memory gets hotplugged
> into the system via memremap_pages() called from a driver, their respective
> memory sections will not have SECTION_IS_EARLY set.
>
> Normal hotplug memory will never have MEMBLOCK_NOMAP set in their memblock
> regions. Because the flag MEMBLOCK_NOMAP was specifically designed and set
> for firmware reserved memory regions. memblock_is_map_memory() can just be
> skipped as its always going to be positive and that will be an optimization
> for the normal hotplug memory. Like ZONE_DEVICE based memory, all normal
> hotplugged memory too will not have SECTION_IS_EARLY set for their sections
>
> Skipping memblock_is_map_memory() for all non early memory sections would
> fix pfn_valid() problem for ZONE_DEVICE based memory and also improve its
> performance for normal hotplug memory as well.
>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Ard Biesheuvel <[email protected]>
> Cc: Robin Murphy <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Acked-by: David Hildenbrand <[email protected]>
> Fixes: 73b20c84d42d ("arm64: mm: implement pte_devmap support")
> Signed-off-by: Anshuman Khandual <[email protected]>
> ---
> arch/arm64/mm/init.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 0ace5e68efba..5920c527845a 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -230,6 +230,18 @@ int pfn_valid(unsigned long pfn)
>
> if (!valid_section(__pfn_to_section(pfn)))
> return 0;
> +
> + /*
> + * ZONE_DEVICE memory does not have the memblock entries.
> + * memblock_is_map_memory() check for ZONE_DEVICE based
> + * addresses will always fail. Even the normal hotplugged
> + * memory will never have MEMBLOCK_NOMAP flag set in their
> + * memblock entries. Skip memblock search for all non early
> + * memory sections covering all of hotplug memory including
> + * both normal and ZONE_DEVICE based.
> + */
> + if (!early_section(__pfn_to_section(pfn)))
> + return pfn_section_valid(__pfn_to_section(pfn), pfn);

Would something like this work instead:

if (online_device_section(ms))
return 1;

to avoid the assumptions around early_section()?

--
Catalin

2021-03-05 18:18:38

by Veronika Kabatova

[permalink] [raw]
Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory



----- Original Message -----
> From: "Veronika Kabatova" <[email protected]>
> To: "Anshuman Khandual" <[email protected]>
> Cc: [email protected], [email protected], [email protected], "Catalin Marinas"
> <[email protected]>, "Will Deacon" <[email protected]>, "Ard Biesheuvel" <[email protected]>, "Mark Rutland"
> <[email protected]>, "James Morse" <[email protected]>, "Robin Murphy" <[email protected]>, "Jérôme Glisse"
> <[email protected]>, "Dan Williams" <[email protected]>, "David Hildenbrand" <[email protected]>, "Mike
> Rapoport" <[email protected]>
> Sent: Friday, March 5, 2021 1:28:40 PM
> Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory
>
>
>
> ----- Original Message -----
> > From: "Anshuman Khandual" <[email protected]>
> > To: [email protected], [email protected],
> > [email protected]
> > Cc: "Catalin Marinas" <[email protected]>, "Will Deacon"
> > <[email protected]>, "Ard Biesheuvel" <[email protected]>,
> > "Mark Rutland" <[email protected]>, "James Morse" <[email protected]>,
> > "Robin Murphy" <[email protected]>,
> > "Jérôme Glisse" <[email protected]>, "Dan Williams"
> > <[email protected]>, "David Hildenbrand"
> > <[email protected]>, "Mike Rapoport" <[email protected]>, "Veronika
> > Kabatova" <[email protected]>
> > Sent: Friday, March 5, 2021 6:38:14 AM
> > Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based
> > memory
> >
> >
> > On 3/5/21 10:54 AM, Anshuman Khandual wrote:
> > > This series fixes pfn_valid() for ZONE_DEVICE based memory and also
> > > improves
> > > its performance for normal hotplug memory. While here, it also
> > > reorganizes
> > > pfn_valid() on CONFIG_SPARSEMEM. This series is based on v5.12-rc1.
> > >
> > > Cc: Catalin Marinas <[email protected]>
> > > Cc: Will Deacon <[email protected]>
> > > Cc: Ard Biesheuvel <[email protected]>
> > > Cc: Mark Rutland <[email protected]>
> > > Cc: James Morse <[email protected]>
> > > Cc: Robin Murphy <[email protected]>
> > > Cc: Jérôme Glisse <[email protected]>
> > > Cc: Dan Williams <[email protected]>
> > > Cc: David Hildenbrand <[email protected]>
> > > Cc: Mike Rapoport <[email protected]>
> > > Cc: Veronika Kabatova <[email protected]>
> > > Cc: [email protected]
> > > Cc: [email protected]
> > > Cc: [email protected]
> > >
> > > Changes in V3:
> > >
> > > - Validate the pfn before fetching mem_section with __pfn_to_section() in
> > > [PATCH 2/2]
> >
> > Hello Veronica,
> >
> > Could you please help recreate the earlier failure [1] but with this
> > series applies on v5.12-rc1. Thank you.
> >
>
> Hello Anshuman,
>
> the machine in question is currently loaned to a developer. I'll reach
> out to them and will let you know once I have any results.
>

Hi,

I'm happy to report the kernel boots with these new patches. I used the
5.12.0-rc1 kernel (commit 280d542f6ffac0) as a base. The full console log
from the boot process is available at

https://gitlab.com/-/snippets/2086833

in case you want to take a look. Note that there are some call traces
starting around line 3220, but they are NOT introduced by these two
patches and are also present with the base mainline kernel.


Veronika

>
> Veronika
>
> > [1]
> > https://lore.kernel.org/linux-arm-kernel/[email protected]/
> >
> > - Anshuman
> >
> >
>

2021-03-05 18:25:02

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

On Fri, Mar 05, 2021 at 01:16:28PM -0500, Veronika Kabatova wrote:
> > > On 3/5/21 10:54 AM, Anshuman Khandual wrote:
> > > > This series fixes pfn_valid() for ZONE_DEVICE based memory and
> > > > also improves its performance for normal hotplug memory. While
> > > > here, it also reorganizes pfn_valid() on CONFIG_SPARSEMEM. This
> > > > series is based on v5.12-rc1.
[...]
> > > Could you please help recreate the earlier failure [1] but with this
> > > series applies on v5.12-rc1. Thank you.
> >
> > the machine in question is currently loaned to a developer. I'll reach
> > out to them and will let you know once I have any results.
>
> I'm happy to report the kernel boots with these new patches. I used the
> 5.12.0-rc1 kernel (commit 280d542f6ffac0) as a base. The full console log
> from the boot process is available at
>
> https://gitlab.com/-/snippets/2086833

That's great Veronika. Thanks for confirming.

--
Catalin

2021-03-05 18:26:09

by David Hildenbrand

[permalink] [raw]
Subject: Re: [PATCH V3 1/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

On 05.03.21 19:13, Catalin Marinas wrote:
> On Fri, Mar 05, 2021 at 10:54:57AM +0530, Anshuman Khandual wrote:
>> pfn_valid() validates a pfn but basically it checks for a valid struct page
>> backing for that pfn. It should always return positive for memory ranges
>> backed with struct page mapping. But currently pfn_valid() fails for all
>> ZONE_DEVICE based memory types even though they have struct page mapping.
>>
>> pfn_valid() asserts that there is a memblock entry for a given pfn without
>> MEMBLOCK_NOMAP flag being set. The problem with ZONE_DEVICE based memory is
>> that they do not have memblock entries. Hence memblock_is_map_memory() will
>> invariably fail via memblock_search() for a ZONE_DEVICE based address. This
>> eventually fails pfn_valid() which is wrong. memblock_is_map_memory() needs
>> to be skipped for such memory ranges. As ZONE_DEVICE memory gets hotplugged
>> into the system via memremap_pages() called from a driver, their respective
>> memory sections will not have SECTION_IS_EARLY set.
>>
>> Normal hotplug memory will never have MEMBLOCK_NOMAP set in their memblock
>> regions. Because the flag MEMBLOCK_NOMAP was specifically designed and set
>> for firmware reserved memory regions. memblock_is_map_memory() can just be
>> skipped as its always going to be positive and that will be an optimization
>> for the normal hotplug memory. Like ZONE_DEVICE based memory, all normal
>> hotplugged memory too will not have SECTION_IS_EARLY set for their sections
>>
>> Skipping memblock_is_map_memory() for all non early memory sections would
>> fix pfn_valid() problem for ZONE_DEVICE based memory and also improve its
>> performance for normal hotplug memory as well.
>>
>> Cc: Catalin Marinas <[email protected]>
>> Cc: Will Deacon <[email protected]>
>> Cc: Ard Biesheuvel <[email protected]>
>> Cc: Robin Murphy <[email protected]>
>> Cc: [email protected]
>> Cc: [email protected]
>> Acked-by: David Hildenbrand <[email protected]>
>> Fixes: 73b20c84d42d ("arm64: mm: implement pte_devmap support")
>> Signed-off-by: Anshuman Khandual <[email protected]>
>> ---
>> arch/arm64/mm/init.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>> index 0ace5e68efba..5920c527845a 100644
>> --- a/arch/arm64/mm/init.c
>> +++ b/arch/arm64/mm/init.c
>> @@ -230,6 +230,18 @@ int pfn_valid(unsigned long pfn)
>>
>> if (!valid_section(__pfn_to_section(pfn)))
>> return 0;
>> +
>> + /*
>> + * ZONE_DEVICE memory does not have the memblock entries.
>> + * memblock_is_map_memory() check for ZONE_DEVICE based
>> + * addresses will always fail. Even the normal hotplugged
>> + * memory will never have MEMBLOCK_NOMAP flag set in their
>> + * memblock entries. Skip memblock search for all non early
>> + * memory sections covering all of hotplug memory including
>> + * both normal and ZONE_DEVICE based.
>> + */
>> + if (!early_section(__pfn_to_section(pfn)))
>> + return pfn_section_valid(__pfn_to_section(pfn), pfn);
>
> Would something like this work instead:
>
> if (online_device_section(ms))
> return 1;
>
> to avoid the assumptions around early_section()?
>

Please keep online section logic out of pfn valid logic. Tow different
things. (and rather not diverge too much from generic pfn_valid() - we
want to achieve the opposite in the long term, merging both implementations)

--
Thanks,

David / dhildenb

2021-03-08 11:33:40

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH V3 1/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

On Fri, Mar 05, 2021 at 07:24:21PM +0100, David Hildenbrand wrote:
> On 05.03.21 19:13, Catalin Marinas wrote:
> > On Fri, Mar 05, 2021 at 10:54:57AM +0530, Anshuman Khandual wrote:
> > > pfn_valid() validates a pfn but basically it checks for a valid struct page
> > > backing for that pfn. It should always return positive for memory ranges
> > > backed with struct page mapping. But currently pfn_valid() fails for all
> > > ZONE_DEVICE based memory types even though they have struct page mapping.
> > >
> > > pfn_valid() asserts that there is a memblock entry for a given pfn without
> > > MEMBLOCK_NOMAP flag being set. The problem with ZONE_DEVICE based memory is
> > > that they do not have memblock entries. Hence memblock_is_map_memory() will
> > > invariably fail via memblock_search() for a ZONE_DEVICE based address. This
> > > eventually fails pfn_valid() which is wrong. memblock_is_map_memory() needs
> > > to be skipped for such memory ranges. As ZONE_DEVICE memory gets hotplugged
> > > into the system via memremap_pages() called from a driver, their respective
> > > memory sections will not have SECTION_IS_EARLY set.
> > >
> > > Normal hotplug memory will never have MEMBLOCK_NOMAP set in their memblock
> > > regions. Because the flag MEMBLOCK_NOMAP was specifically designed and set
> > > for firmware reserved memory regions. memblock_is_map_memory() can just be
> > > skipped as its always going to be positive and that will be an optimization
> > > for the normal hotplug memory. Like ZONE_DEVICE based memory, all normal
> > > hotplugged memory too will not have SECTION_IS_EARLY set for their sections
> > >
> > > Skipping memblock_is_map_memory() for all non early memory sections would
> > > fix pfn_valid() problem for ZONE_DEVICE based memory and also improve its
> > > performance for normal hotplug memory as well.
> > >
> > > Cc: Catalin Marinas <[email protected]>
> > > Cc: Will Deacon <[email protected]>
> > > Cc: Ard Biesheuvel <[email protected]>
> > > Cc: Robin Murphy <[email protected]>
> > > Cc: [email protected]
> > > Cc: [email protected]
> > > Acked-by: David Hildenbrand <[email protected]>
> > > Fixes: 73b20c84d42d ("arm64: mm: implement pte_devmap support")
> > > Signed-off-by: Anshuman Khandual <[email protected]>
> > > ---
> > > arch/arm64/mm/init.c | 12 ++++++++++++
> > > 1 file changed, 12 insertions(+)
> > >
> > > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> > > index 0ace5e68efba..5920c527845a 100644
> > > --- a/arch/arm64/mm/init.c
> > > +++ b/arch/arm64/mm/init.c
> > > @@ -230,6 +230,18 @@ int pfn_valid(unsigned long pfn)
> > > if (!valid_section(__pfn_to_section(pfn)))
> > > return 0;
> > > +
> > > + /*
> > > + * ZONE_DEVICE memory does not have the memblock entries.
> > > + * memblock_is_map_memory() check for ZONE_DEVICE based
> > > + * addresses will always fail. Even the normal hotplugged
> > > + * memory will never have MEMBLOCK_NOMAP flag set in their
> > > + * memblock entries. Skip memblock search for all non early
> > > + * memory sections covering all of hotplug memory including
> > > + * both normal and ZONE_DEVICE based.
> > > + */
> > > + if (!early_section(__pfn_to_section(pfn)))
> > > + return pfn_section_valid(__pfn_to_section(pfn), pfn);
> >
> > Would something like this work instead:
> >
> > if (online_device_section(ms))
> > return 1;
> >
> > to avoid the assumptions around early_section()?
>
> Please keep online section logic out of pfn valid logic. Tow different
> things. (and rather not diverge too much from generic pfn_valid() - we want
> to achieve the opposite in the long term, merging both implementations)

I think I misread the code. I was looking for a new flag to check like
SECTION_IS_DEVICE instead of assuming that !SECTION_IS_EARLY means
device or mhp.

Anyway, staring at this code for a bit more, I came to the conclusion
that the logic in Anshuman's patches is fairly robust - we only need to
check for memblock_is_map_memory() if early_section() as that's the only
case where we can have MEMBLOCK_NOMAP. Maybe the comment above should be
re-written a bit and avoid the ZONE_DEVICE and hotplugged memory
details altogether.

--
Catalin

2021-03-08 18:01:12

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH V3 1/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

On Fri, Mar 05, 2021 at 10:54:57AM +0530, Anshuman Khandual wrote:
> pfn_valid() validates a pfn but basically it checks for a valid struct page
> backing for that pfn. It should always return positive for memory ranges
> backed with struct page mapping. But currently pfn_valid() fails for all
> ZONE_DEVICE based memory types even though they have struct page mapping.
>
> pfn_valid() asserts that there is a memblock entry for a given pfn without
> MEMBLOCK_NOMAP flag being set. The problem with ZONE_DEVICE based memory is
> that they do not have memblock entries. Hence memblock_is_map_memory() will
> invariably fail via memblock_search() for a ZONE_DEVICE based address. This
> eventually fails pfn_valid() which is wrong. memblock_is_map_memory() needs
> to be skipped for such memory ranges. As ZONE_DEVICE memory gets hotplugged
> into the system via memremap_pages() called from a driver, their respective
> memory sections will not have SECTION_IS_EARLY set.
>
> Normal hotplug memory will never have MEMBLOCK_NOMAP set in their memblock
> regions. Because the flag MEMBLOCK_NOMAP was specifically designed and set
> for firmware reserved memory regions. memblock_is_map_memory() can just be
> skipped as its always going to be positive and that will be an optimization
> for the normal hotplug memory. Like ZONE_DEVICE based memory, all normal
> hotplugged memory too will not have SECTION_IS_EARLY set for their sections
>
> Skipping memblock_is_map_memory() for all non early memory sections would
> fix pfn_valid() problem for ZONE_DEVICE based memory and also improve its
> performance for normal hotplug memory as well.
>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Ard Biesheuvel <[email protected]>
> Cc: Robin Murphy <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Acked-by: David Hildenbrand <[email protected]>
> Fixes: 73b20c84d42d ("arm64: mm: implement pte_devmap support")
> Signed-off-by: Anshuman Khandual <[email protected]>
> ---
> arch/arm64/mm/init.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 0ace5e68efba..5920c527845a 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -230,6 +230,18 @@ int pfn_valid(unsigned long pfn)
>
> if (!valid_section(__pfn_to_section(pfn)))
> return 0;
> +
> + /*
> + * ZONE_DEVICE memory does not have the memblock entries.
> + * memblock_is_map_memory() check for ZONE_DEVICE based
> + * addresses will always fail. Even the normal hotplugged
> + * memory will never have MEMBLOCK_NOMAP flag set in their
> + * memblock entries. Skip memblock search for all non early
> + * memory sections covering all of hotplug memory including
> + * both normal and ZONE_DEVICE based.
> + */
> + if (!early_section(__pfn_to_section(pfn)))
> + return pfn_section_valid(__pfn_to_section(pfn), pfn);
> #endif
> return memblock_is_map_memory(addr);
> }

Acked-by: Catalin Marinas <[email protected]>

2021-03-08 18:05:25

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH V3 2/2] arm64/mm: Reorganize pfn_valid()

On Fri, Mar 05, 2021 at 10:54:58AM +0530, Anshuman Khandual wrote:
> There are multiple instances of pfn_to_section_nr() and __pfn_to_section()
> when CONFIG_SPARSEMEM is enabled. This can be optimized if memory section
> is fetched earlier. This replaces the open coded PFN and ADDR conversion
> with PFN_PHYS() and PHYS_PFN() helpers. While there, also add a comment.
> This does not cause any functional change.
>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Ard Biesheuvel <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Reviewed-by: David Hildenbrand <[email protected]>
> Signed-off-by: Anshuman Khandual <[email protected]>

Acked-by: Catalin Marinas <[email protected]>

2021-03-08 19:20:32

by Will Deacon

[permalink] [raw]
Subject: Re: [PATCH V3 0/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory

On Fri, 5 Mar 2021 10:54:56 +0530, Anshuman Khandual wrote:
> This series fixes pfn_valid() for ZONE_DEVICE based memory and also improves
> its performance for normal hotplug memory. While here, it also reorganizes
> pfn_valid() on CONFIG_SPARSEMEM. This series is based on v5.12-rc1.
>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Ard Biesheuvel <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: James Morse <[email protected]>
> Cc: Robin Murphy <[email protected]>
> Cc: Jérôme Glisse <[email protected]>
> Cc: Dan Williams <[email protected]>
> Cc: David Hildenbrand <[email protected]>
> Cc: Mike Rapoport <[email protected]>
> Cc: Veronika Kabatova <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
>
> [...]

Applied to arm64 (for-next/fixes), thanks!

[1/2] arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory
https://git.kernel.org/arm64/c/eeb0753ba27b
[2/2] arm64/mm: Reorganize pfn_valid()
https://git.kernel.org/arm64/c/093bbe211ea5

Cheers,
--
Will

https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev