Hi Waiman, On 6/26/2024 5:46 AM, Waiman Long wrote: > Commit 5ec8e8ea8b77 ("mm/sparsemem: fix race in accessing > memory_section->usage") changed pfn_section_valid() to add a READ_ONCE() > call around "ms->usage" to fix a race with section_deactivate() where > ms->usage can be cleared. The READ_ONCE() call, by itself, is not enough > to prevent NULL pointer dereference. We need to check its value before > dereferencing it. I am unable to see a scenario where ms->usage will be NULL when pfn_section_valid() is called: 1) In pfn_valid, valid_section() check ensures that pfn_section_valid() is not called as the section is marked as invalid. 2) In pfn_to_online_page, online_section() check ensures that pfn_section_valid() is not called. and in the update path, we do: kfree_rcu(ms->usage, rcu); WRITE_ONCE(ms->usage, NULL); Could you help me in understanding about what I am missing here, please? > > Fixes: 5ec8e8ea8b77 ("mm/sparsemem: fix race in accessing memory_section->usage") > Signed-off-by: Waiman Long <longman@xxxxxxxxxx> > --- > include/linux/mmzone.h | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h > index 8f9c9590a42c..b1dcf6ddb406 100644 > --- a/include/linux/mmzone.h > +++ b/include/linux/mmzone.h > @@ -1980,8 +1980,9 @@ static inline int subsection_map_index(unsigned long pfn) > static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn) > { > int idx = subsection_map_index(pfn); > + struct mem_section_usage *usage = READ_ONCE(ms->usage); > > - return test_bit(idx, READ_ONCE(ms->usage)->subsection_map); > + return usage ? test_bit(idx, usage->subsection_map) : 0; > } > #else > static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)