Unverified Commit c3a5ce23 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!5494 mm/sparsemem: fix race in accessing memory_section->usage

parents 0d30c7f2 31fcbdee
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -1229,6 +1229,7 @@ struct mem_section_usage {
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	DECLARE_BITMAP(subsection_map, SUBSECTIONS_PER_SECTION);
#endif
	KABI_EXTEND(struct rcu_head rcu)
	/* See declaration of similar field in struct zone */
	unsigned long pageblock_flags[0];
};
@@ -1391,7 +1392,7 @@ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
{
	int idx = subsection_map_index(pfn);

	return test_bit(idx, ms->usage->subsection_map);
	return test_bit(idx, READ_ONCE(ms->usage)->subsection_map);
}
#else
static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
@@ -1404,17 +1405,25 @@ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
static inline int pfn_valid(unsigned long pfn)
{
	struct mem_section *ms;
	int ret;

	if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
		return 0;
	ms = __nr_to_section(pfn_to_section_nr(pfn));
	if (!valid_section(ms))
	rcu_read_lock();
	if (!valid_section(ms)) {
		rcu_read_unlock();
		return 0;
	}

	/*
	 * Traditionally early sections always returned pfn_valid() for
	 * the entire section-sized span.
	 */
	return early_section(ms) || pfn_section_valid(ms, pfn);
	ret = early_section(ms) || pfn_section_valid(ms, pfn);
	rcu_read_unlock();

	return ret;
}
#endif

+9 −8
Original line number Diff line number Diff line
@@ -809,6 +809,13 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
	if (empty) {
		unsigned long section_nr = pfn_to_section_nr(pfn);

		/*
		 * Mark the section invalid so that valid_section()
		 * return false. This prevents code from dereferencing
		 * ms->usage array.
		 */
		ms->section_mem_map &= ~SECTION_HAS_MEM_MAP;

		/*
		 * When removing an early section, the usage map is kept (as the
		 * usage maps of other sections fall into the same page). It
@@ -817,16 +824,10 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
		 * was allocated during boot.
		 */
		if (!PageReserved(virt_to_page(ms->usage))) {
			kfree(ms->usage);
			ms->usage = NULL;
			kfree_rcu(ms->usage, rcu);
			WRITE_ONCE(ms->usage, NULL);
		}
		memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
		/*
		 * Mark the section invalid so that valid_section()
		 * return false. This prevents code from dereferencing
		 * ms->usage array.
		 */
		ms->section_mem_map &= ~SECTION_HAS_MEM_MAP;
	}

	/*