Re: [RFC PATCH 3/3] mm: Implement for_each_valid_pfn() for CONFIG_SPARSEMEM
From: Mike Rapoport
Date: Thu Apr 03 2025 - 02:25:18 EST
On Wed, Apr 02, 2025 at 09:18:41PM +0100, David Woodhouse wrote:
> From: David Woodhouse <dwmw@xxxxxxxxxxxx>
>
> 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@xxxxxxxxxxxx>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
with a small nit below
> +static inline bool first_valid_pfn(unsigned long *p_pfn)
> +{
> + unsigned long pfn = *p_pfn;
> + unsigned long nr = pfn_to_section_nr(pfn);
> + struct mem_section *ms;
> + bool ret = false;
> +
> + ms = __pfn_to_section(pfn);
> +
> + rcu_read_lock_sched();
> +
> + while (!ret && nr <= __highest_present_section_nr) {
This could be just for(;;), we anyway break when ret becomes true or we get
past last present section.
> + if (valid_section(ms) &&
> + (early_section(ms) || pfn_section_first_valid(ms, &pfn))) {
> + ret = true;
> + break;
> + }
> +
> + nr++;
> + if (nr > __highest_present_section_nr)
> + break;
> +
> + pfn = section_nr_to_pfn(nr);
> + ms = __pfn_to_section(pfn);
> + }
> +
> + rcu_read_unlock_sched();
> +
> + *p_pfn = pfn;
> +
> + return ret;
> +}
> +
> +#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
>
--
Sincerely yours,
Mike.