* [RFC PATCH v2 2/7] mm: Implement for_each_valid_pfn() for CONFIG_FLATMEM
2025-04-04 15:59 [RFC PATCH v2 1/7] mm: Introduce for_each_valid_pfn() and use it from reserve_bootmem_region() David Woodhouse
@ 2025-04-04 15:59 ` David Woodhouse
2025-04-07 6:54 ` Mike Rapoport
2025-04-04 15:59 ` [RFC PATCH v2 3/7] mm: Implement for_each_valid_pfn() for CONFIG_SPARSEMEM David Woodhouse
` (4 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: David Woodhouse @ 2025-04-04 15:59 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
From: David Woodhouse <dwmw@amazon.co.uk>
In the FLATMEM case, the default pfn_valid() just checks that the PFN is
within the range [ ARCH_PFN_OFFSET .. ARCH_PFN_OFFSET + max_mapnr ).
The for_each_valid_pfn() function can therefore be a simple for() loop
using those as min/max respectively.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
include/asm-generic/memory_model.h | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index a3b5029aebbd..044536da3390 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -30,7 +30,31 @@ static inline int pfn_valid(unsigned long pfn)
return pfn >= pfn_offset && (pfn - pfn_offset) < max_mapnr;
}
#define pfn_valid pfn_valid
-#endif
+
+static inline bool first_valid_pfn(unsigned long *pfn)
+{
+ /* avoid <linux/mm.h> include hell */
+ extern unsigned long max_mapnr;
+ unsigned long pfn_offset = ARCH_PFN_OFFSET;
+
+ if (*pfn < pfn_offset) {
+ *pfn = pfn_offset;
+ return true;
+ }
+
+ if ((*pfn - pfn_offset) < max_mapnr)
+ return true;
+
+ return false;
+}
+
+#ifndef for_each_valid_pfn
+#define for_each_valid_pfn(pfn, start_pfn, end_pfn) \
+ for (pfn = max_t(unsigned long, start_pfn, ARCH_PFN_OFFSET); \
+ pfn < min_t(unsigned long, end_pfn, ARCH_PFN_OFFSET + max_mapnr); \
+ pfn++)
+#endif /* for_each_valid_pfn */
+#endif /* valid_pfn */
#elif defined(CONFIG_SPARSEMEM_VMEMMAP)
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC PATCH v2 2/7] mm: Implement for_each_valid_pfn() for CONFIG_FLATMEM
2025-04-04 15:59 ` [RFC PATCH v2 2/7] mm: Implement for_each_valid_pfn() for CONFIG_FLATMEM David Woodhouse
@ 2025-04-07 6:54 ` Mike Rapoport
2025-04-07 7:56 ` David Woodhouse
0 siblings, 1 reply; 11+ messages in thread
From: Mike Rapoport @ 2025-04-07 6:54 UTC (permalink / raw)
To: David Woodhouse
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
On Fri, Apr 04, 2025 at 04:59:54PM +0100, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
>
> In the FLATMEM case, the default pfn_valid() just checks that the PFN is
> within the range [ ARCH_PFN_OFFSET .. ARCH_PFN_OFFSET + max_mapnr ).
>
> The for_each_valid_pfn() function can therefore be a simple for() loop
> using those as min/max respectively.
>
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> include/asm-generic/memory_model.h | 26 +++++++++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
> index a3b5029aebbd..044536da3390 100644
> --- a/include/asm-generic/memory_model.h
> +++ b/include/asm-generic/memory_model.h
> @@ -30,7 +30,31 @@ static inline int pfn_valid(unsigned long pfn)
> return pfn >= pfn_offset && (pfn - pfn_offset) < max_mapnr;
> }
> #define pfn_valid pfn_valid
> -#endif
> +
> +static inline bool first_valid_pfn(unsigned long *pfn)
This is now different from SPARSEMEM version. Do we need it at all?
> +{
> + /* avoid <linux/mm.h> include hell */
>
> + extern unsigned long max_mapnr;
> + unsigned long pfn_offset = ARCH_PFN_OFFSET;
> +
> + if (*pfn < pfn_offset) {
> + *pfn = pfn_offset;
> + return true;
> + }
> +
> + if ((*pfn - pfn_offset) < max_mapnr)
> + return true;
> +
> + return false;
> +}
> +
> +#ifndef for_each_valid_pfn
> +#define for_each_valid_pfn(pfn, start_pfn, end_pfn) \
> + for (pfn = max_t(unsigned long, start_pfn, ARCH_PFN_OFFSET); \
> + pfn < min_t(unsigned long, end_pfn, ARCH_PFN_OFFSET + max_mapnr); \
> + pfn++)
> +#endif /* for_each_valid_pfn */
> +#endif /* valid_pfn */
>
> #elif defined(CONFIG_SPARSEMEM_VMEMMAP)
>
> --
> 2.49.0
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC PATCH v2 2/7] mm: Implement for_each_valid_pfn() for CONFIG_FLATMEM
2025-04-07 6:54 ` Mike Rapoport
@ 2025-04-07 7:56 ` David Woodhouse
0 siblings, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2025-04-07 7:56 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
[-- Attachment #1: Type: text/plain, Size: 754 bytes --]
On Mon, 2025-04-07 at 09:54 +0300, Mike Rapoport wrote:
> el.h b/include/asm-generic/memory_model.h
> > index a3b5029aebbd..044536da3390 100644
> > --- a/include/asm-generic/memory_model.h
> > +++ b/include/asm-generic/memory_model.h
> > @@ -30,7 +30,31 @@ static inline int pfn_valid(unsigned long pfn)
> > return pfn >= pfn_offset && (pfn - pfn_offset) <
> > max_mapnr;
> > }
> > #define pfn_valid pfn_valid
> > -#endif
> > +
> > +static inline bool first_valid_pfn(unsigned long *pfn)
>
> This is now different from SPARSEMEM version. Do we need it at all?
Er, no. I think it's left over from the first implementation, before I
realised I could put it all into the loop and didn't need a helper at
all. I'll remove it.
[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC PATCH v2 3/7] mm: Implement for_each_valid_pfn() for CONFIG_SPARSEMEM
2025-04-04 15:59 [RFC PATCH v2 1/7] mm: Introduce for_each_valid_pfn() and use it from reserve_bootmem_region() David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 2/7] mm: Implement for_each_valid_pfn() for CONFIG_FLATMEM David Woodhouse
@ 2025-04-04 15:59 ` David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 4/7] mm: Optimise SPARSEMEM implementation of for_each_valid_pfn() David Woodhouse
` (3 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2025-04-04 15:59 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
From: David Woodhouse <dwmw@amazon.co.uk>
Introduce a pfn_first_valid() helper which takes a pointer to the PFN and
updates it to point to the first valid PFN starting from that point, and
returns true if a valid PFN was found.
This largely mirrors pfn_valid(), calling into a pfn_section_first_valid()
helper which is trivial for the !CONFIG_SPARSEMEM_VMEMMAP case, and in
the VMEMMAP case will skip to the next subsection as needed.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
include/linux/mmzone.h | 59 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 32ecb5cadbaf..67cdf675a4b9 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -2074,11 +2074,37 @@ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
return usage ? test_bit(idx, usage->subsection_map) : 0;
}
+
+static inline bool pfn_section_first_valid(struct mem_section *ms, unsigned long *pfn)
+{
+ struct mem_section_usage *usage = READ_ONCE(ms->usage);
+ int idx = subsection_map_index(*pfn);
+ unsigned long bit;
+
+ if (!usage)
+ return false;
+
+ if (test_bit(idx, usage->subsection_map))
+ return true;
+
+ /* Find the next subsection that exists */
+ bit = find_next_bit(usage->subsection_map, SUBSECTIONS_PER_SECTION, idx);
+ if (bit == SUBSECTIONS_PER_SECTION)
+ return false;
+
+ *pfn = (*pfn & PAGE_SECTION_MASK) + (bit * PAGES_PER_SUBSECTION);
+ return true;
+}
#else
static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
{
return 1;
}
+
+static inline bool pfn_section_first_valid(struct mem_section *ms, unsigned long *pfn)
+{
+ return true;
+}
#endif
void sparse_init_early_section(int nid, struct page *map, unsigned long pnum,
@@ -2127,6 +2153,39 @@ static inline int pfn_valid(unsigned long pfn)
return ret;
}
+
+static inline bool first_valid_pfn(unsigned long *p_pfn)
+{
+ unsigned long pfn = *p_pfn;
+ unsigned long nr = pfn_to_section_nr(pfn);
+
+ rcu_read_lock_sched();
+
+ while (nr <= __highest_present_section_nr) {
+ struct mem_section *ms = __pfn_to_section(pfn);
+
+ if (valid_section(ms) &&
+ (early_section(ms) || pfn_section_first_valid(ms, &pfn))) {
+ *p_pfn = pfn;
+ rcu_read_unlock_sched();
+ return true;
+ }
+
+ /* Nothing left in this section? Skip to next section */
+ nr++;
+ pfn = section_nr_to_pfn(nr);
+ }
+
+ rcu_read_unlock_sched();
+
+ return false;
+}
+
+#define for_each_valid_pfn(_pfn, _start_pfn, _end_pfn) \
+ for ((_pfn) = (_start_pfn); \
+ first_valid_pfn(&(_pfn)) && (_pfn) < (_end_pfn); \
+ (_pfn)++)
+
#endif
static inline int pfn_in_present_section(unsigned long pfn)
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH v2 4/7] mm: Optimise SPARSEMEM implementation of for_each_valid_pfn()
2025-04-04 15:59 [RFC PATCH v2 1/7] mm: Introduce for_each_valid_pfn() and use it from reserve_bootmem_region() David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 2/7] mm: Implement for_each_valid_pfn() for CONFIG_FLATMEM David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 3/7] mm: Implement for_each_valid_pfn() for CONFIG_SPARSEMEM David Woodhouse
@ 2025-04-04 15:59 ` David Woodhouse
2025-04-07 7:07 ` Mike Rapoport
2025-04-04 15:59 ` [RFC PATCH v2 5/7] mm, PM: Use for_each_valid_pfn() in kernel/power/snapshot.c David Woodhouse
` (2 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: David Woodhouse @ 2025-04-04 15:59 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
From: David Woodhouse <dwmw@amazon.co.uk>
There's no point in checking the section and subsection bitmap for *every*
PFN in the same section; they're either all valid or they aren't.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
include/linux/mmzone.h | 39 +++++++++++++++++++++++++++++----------
1 file changed, 29 insertions(+), 10 deletions(-)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 67cdf675a4b9..0da1b0ba5d9f 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -2154,21 +2154,20 @@ static inline int pfn_valid(unsigned long pfn)
return ret;
}
-static inline bool first_valid_pfn(unsigned long *p_pfn)
+/* Returns -1 (an invalid PFN) if no valid PFN remaining */
+static inline unsigned long first_valid_pfn(unsigned long pfn, unsigned long end_pfn)
{
- unsigned long pfn = *p_pfn;
unsigned long nr = pfn_to_section_nr(pfn);
rcu_read_lock_sched();
- while (nr <= __highest_present_section_nr) {
+ while (nr <= __highest_present_section_nr && pfn < end_pfn) {
struct mem_section *ms = __pfn_to_section(pfn);
if (valid_section(ms) &&
(early_section(ms) || pfn_section_first_valid(ms, &pfn))) {
- *p_pfn = pfn;
rcu_read_unlock_sched();
- return true;
+ return pfn;
}
/* Nothing left in this section? Skip to next section */
@@ -2177,14 +2176,34 @@ static inline bool first_valid_pfn(unsigned long *p_pfn)
}
rcu_read_unlock_sched();
+ return (unsigned long)-1;
+}
- return false;
+static inline unsigned long next_valid_pfn(unsigned long pfn, unsigned long end_pfn)
+{
+ pfn++;
+
+ if (pfn >= end_pfn)
+ return (unsigned long)-1;
+
+ /*
+ * Either every PFN within the section (or subsection for VMEMMAP) is
+ * valid, or none of them are. So there's no point repeating the check
+ * for every PFN; only call first_valid_pfn() the first time, and when
+ * crossing a (sub)section boundary (i.e. !(pfn & ~PFN_VALID_MASK)).
+ */
+ if (pfn & (IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP) ?
+ PAGE_SUBSECTION_MASK : PAGE_SECTION_MASK))
+ return pfn;
+
+ return first_valid_pfn(pfn, end_pfn);
}
-#define for_each_valid_pfn(_pfn, _start_pfn, _end_pfn) \
- for ((_pfn) = (_start_pfn); \
- first_valid_pfn(&(_pfn)) && (_pfn) < (_end_pfn); \
- (_pfn)++)
+
+#define for_each_valid_pfn(_pfn, _start_pfn, _end_pfn) \
+ for ((_pfn) = first_valid_pfn((_start_pfn), (_end_pfn)); \
+ (_pfn) != (unsigned long)-1; \
+ (_pfn) = next_valid_pfn((_pfn), (_end_pfn)))
#endif
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC PATCH v2 4/7] mm: Optimise SPARSEMEM implementation of for_each_valid_pfn()
2025-04-04 15:59 ` [RFC PATCH v2 4/7] mm: Optimise SPARSEMEM implementation of for_each_valid_pfn() David Woodhouse
@ 2025-04-07 7:07 ` Mike Rapoport
2025-04-07 8:01 ` David Woodhouse
0 siblings, 1 reply; 11+ messages in thread
From: Mike Rapoport @ 2025-04-07 7:07 UTC (permalink / raw)
To: David Woodhouse
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
On Fri, Apr 04, 2025 at 04:59:56PM +0100, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
>
> There's no point in checking the section and subsection bitmap for *every*
> PFN in the same section; they're either all valid or they aren't.
Don't you want to merge this with the previous commit?
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
> include/linux/mmzone.h | 39 +++++++++++++++++++++++++++++----------
> 1 file changed, 29 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index 67cdf675a4b9..0da1b0ba5d9f 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -2154,21 +2154,20 @@ static inline int pfn_valid(unsigned long pfn)
> return ret;
> }
>
> -static inline bool first_valid_pfn(unsigned long *p_pfn)
> +/* Returns -1 (an invalid PFN) if no valid PFN remaining */
> +static inline unsigned long first_valid_pfn(unsigned long pfn, unsigned long end_pfn)
> {
> - unsigned long pfn = *p_pfn;
> unsigned long nr = pfn_to_section_nr(pfn);
>
> rcu_read_lock_sched();
>
> - while (nr <= __highest_present_section_nr) {
> + while (nr <= __highest_present_section_nr && pfn < end_pfn) {
> struct mem_section *ms = __pfn_to_section(pfn);
>
> if (valid_section(ms) &&
> (early_section(ms) || pfn_section_first_valid(ms, &pfn))) {
> - *p_pfn = pfn;
> rcu_read_unlock_sched();
> - return true;
> + return pfn;
> }
>
> /* Nothing left in this section? Skip to next section */
> @@ -2177,14 +2176,34 @@ static inline bool first_valid_pfn(unsigned long *p_pfn)
> }
>
> rcu_read_unlock_sched();
> + return (unsigned long)-1;
> +}
>
> - return false;
> +static inline unsigned long next_valid_pfn(unsigned long pfn, unsigned long end_pfn)
> +{
> + pfn++;
> +
> + if (pfn >= end_pfn)
> + return (unsigned long)-1;
> +
> + /*
> + * Either every PFN within the section (or subsection for VMEMMAP) is
> + * valid, or none of them are. So there's no point repeating the check
> + * for every PFN; only call first_valid_pfn() the first time, and when
> + * crossing a (sub)section boundary (i.e. !(pfn & ~PFN_VALID_MASK)).
> + */
> + if (pfn & (IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP) ?
> + PAGE_SUBSECTION_MASK : PAGE_SECTION_MASK))
> + return pfn;
> +
> + return first_valid_pfn(pfn, end_pfn);
> }
>
> -#define for_each_valid_pfn(_pfn, _start_pfn, _end_pfn) \
> - for ((_pfn) = (_start_pfn); \
> - first_valid_pfn(&(_pfn)) && (_pfn) < (_end_pfn); \
> - (_pfn)++)
> +
> +#define for_each_valid_pfn(_pfn, _start_pfn, _end_pfn) \
> + for ((_pfn) = first_valid_pfn((_start_pfn), (_end_pfn)); \
> + (_pfn) != (unsigned long)-1; \
> + (_pfn) = next_valid_pfn((_pfn), (_end_pfn)))
>
> #endif
>
> --
> 2.49.0
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC PATCH v2 4/7] mm: Optimise SPARSEMEM implementation of for_each_valid_pfn()
2025-04-07 7:07 ` Mike Rapoport
@ 2025-04-07 8:01 ` David Woodhouse
0 siblings, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2025-04-07 8:01 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
[-- Attachment #1: Type: text/plain, Size: 911 bytes --]
On Mon, 2025-04-07 at 10:07 +0300, Mike Rapoport wrote:
> On Fri, Apr 04, 2025 at 04:59:56PM +0100, David Woodhouse wrote:
> > From: David Woodhouse <dwmw@amazon.co.uk>
> >
> > There's no point in checking the section and subsection bitmap for *every*
> > PFN in the same section; they're either all valid or they aren't.
>
> Don't you want to merge this with the previous commit?
Maybe. Or at least the previous commit should be using the 'return -1'
model to minimise the differences.
To start with though, I wanted it to be reviewable as an incremental
patch to what we'd already been discussing. (And I figured there was at
least a non-zero chance of you not liking it just because it's too
complex, so the whole thing is easy to drop this way).
Even after review, keeping it as a separate patch means it's easily
revertible if we find we want to go back to the simpler version.
[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC PATCH v2 5/7] mm, PM: Use for_each_valid_pfn() in kernel/power/snapshot.c
2025-04-04 15:59 [RFC PATCH v2 1/7] mm: Introduce for_each_valid_pfn() and use it from reserve_bootmem_region() David Woodhouse
` (2 preceding siblings ...)
2025-04-04 15:59 ` [RFC PATCH v2 4/7] mm: Optimise SPARSEMEM implementation of for_each_valid_pfn() David Woodhouse
@ 2025-04-04 15:59 ` David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 6/7] mm, x86: Use for_each_valid_pfn() from __ioremap_check_ram() David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 7/7] mm: use for_each_valid_pfn() in memory_hotplug David Woodhouse
5 siblings, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2025-04-04 15:59 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
From: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
kernel/power/snapshot.c | 42 ++++++++++++++++++++---------------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 4e6e24e8b854..f151c7a45584 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1094,16 +1094,15 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
((unsigned long long) region->end_pfn << PAGE_SHIFT)
- 1);
- for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
- if (pfn_valid(pfn)) {
- /*
- * It is safe to ignore the result of
- * mem_bm_set_bit_check() here, since we won't
- * touch the PFNs for which the error is
- * returned anyway.
- */
- mem_bm_set_bit_check(bm, pfn);
- }
+ for_each_valid_pfn (pfn, region->start_pfn, region->end_pfn) {
+ /*
+ * It is safe to ignore the result of
+ * mem_bm_set_bit_check() here, since we won't
+ * touch the PFNs for which the error is
+ * returned anyway.
+ */
+ mem_bm_set_bit_check(bm, pfn);
+ }
}
}
@@ -1255,21 +1254,20 @@ static void mark_free_pages(struct zone *zone)
spin_lock_irqsave(&zone->lock, flags);
max_zone_pfn = zone_end_pfn(zone);
- for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
- if (pfn_valid(pfn)) {
- page = pfn_to_page(pfn);
+ for_each_valid_pfn(pfn, zone->zone_start_pfn, max_zone_pfn) {
+ page = pfn_to_page(pfn);
- if (!--page_count) {
- touch_nmi_watchdog();
- page_count = WD_PAGE_COUNT;
- }
+ if (!--page_count) {
+ touch_nmi_watchdog();
+ page_count = WD_PAGE_COUNT;
+ }
- if (page_zone(page) != zone)
- continue;
+ if (page_zone(page) != zone)
+ continue;
- if (!swsusp_page_is_forbidden(page))
- swsusp_unset_page_free(page);
- }
+ if (!swsusp_page_is_forbidden(page))
+ swsusp_unset_page_free(page);
+ }
for_each_migratetype_order(order, t) {
list_for_each_entry(page,
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH v2 6/7] mm, x86: Use for_each_valid_pfn() from __ioremap_check_ram()
2025-04-04 15:59 [RFC PATCH v2 1/7] mm: Introduce for_each_valid_pfn() and use it from reserve_bootmem_region() David Woodhouse
` (3 preceding siblings ...)
2025-04-04 15:59 ` [RFC PATCH v2 5/7] mm, PM: Use for_each_valid_pfn() in kernel/power/snapshot.c David Woodhouse
@ 2025-04-04 15:59 ` David Woodhouse
2025-04-04 15:59 ` [RFC PATCH v2 7/7] mm: use for_each_valid_pfn() in memory_hotplug David Woodhouse
5 siblings, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2025-04-04 15:59 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
From: David Woodhouse <dwmw@amazon.co.uk>
Instead of calling pfn_valid() separately for every single PFN in the
range, use for_each_valid_pfn() and only look at the ones which are.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
arch/x86/mm/ioremap.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 331e101bf801..12c8180ca1ba 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -71,7 +71,7 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
static unsigned int __ioremap_check_ram(struct resource *res)
{
unsigned long start_pfn, stop_pfn;
- unsigned long i;
+ unsigned long pfn;
if ((res->flags & IORESOURCE_SYSTEM_RAM) != IORESOURCE_SYSTEM_RAM)
return 0;
@@ -79,9 +79,8 @@ static unsigned int __ioremap_check_ram(struct resource *res)
start_pfn = (res->start + PAGE_SIZE - 1) >> PAGE_SHIFT;
stop_pfn = (res->end + 1) >> PAGE_SHIFT;
if (stop_pfn > start_pfn) {
- for (i = 0; i < (stop_pfn - start_pfn); ++i)
- if (pfn_valid(start_pfn + i) &&
- !PageReserved(pfn_to_page(start_pfn + i)))
+ for_each_valid_pfn(pfn, start_pfn, stop_pfn)
+ if (!PageReserved(pfn_to_page(pfn)))
return IORES_MAP_SYSTEM_RAM;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH v2 7/7] mm: use for_each_valid_pfn() in memory_hotplug
2025-04-04 15:59 [RFC PATCH v2 1/7] mm: Introduce for_each_valid_pfn() and use it from reserve_bootmem_region() David Woodhouse
` (4 preceding siblings ...)
2025-04-04 15:59 ` [RFC PATCH v2 6/7] mm, x86: Use for_each_valid_pfn() from __ioremap_check_ram() David Woodhouse
@ 2025-04-04 15:59 ` David Woodhouse
5 siblings, 0 replies; 11+ messages in thread
From: David Woodhouse @ 2025-04-04 15:59 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, Sauerwein, David, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Marc Zyngier,
Mark Rutland, Mike Rapoport, Will Deacon, kvmarm,
linux-arm-kernel, linux-kernel, linux-mm
From: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
mm/memory_hotplug.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 75401866fb76..20c39ae45016 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1756,12 +1756,10 @@ static int scan_movable_pages(unsigned long start, unsigned long end,
{
unsigned long pfn;
- for (pfn = start; pfn < end; pfn++) {
+ for_each_valid_pfn (pfn, start, end) {
struct page *page;
struct folio *folio;
- if (!pfn_valid(pfn))
- continue;
page = pfn_to_page(pfn);
if (PageLRU(page))
goto found;
@@ -1805,11 +1803,9 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
static DEFINE_RATELIMIT_STATE(migrate_rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
- for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+ for_each_valid_pfn (pfn, start_pfn, end_pfn) {
struct page *page;
- if (!pfn_valid(pfn))
- continue;
page = pfn_to_page(pfn);
folio = page_folio(page);
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread