1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
From 95fa13c9fe928ae6e21c1554360b5cada74cc857 Mon Sep 17 00:00:00 2001
From: Levente Polyak <levente@leventepolyak.net>
Date: Fri, 2 Feb 2024 02:03:34 +0100
Subject: [PATCH] Revert "mm/sparsemem: fix race in accessing
memory_section->usage"
This reverts commit 3a01daace71b521563c38bbbf874e14c3e58adb7.
---
include/linux/mmzone.h | 14 +++-----------
mm/sparse.c | 17 ++++++++---------
2 files changed, 11 insertions(+), 20 deletions(-)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index a7c32324c263..9db36e197712 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1793,7 +1793,6 @@ static inline unsigned long section_nr_to_pfn(unsigned long sec)
#define SUBSECTION_ALIGN_DOWN(pfn) ((pfn) & PAGE_SUBSECTION_MASK)
struct mem_section_usage {
- struct rcu_head rcu;
#ifdef CONFIG_SPARSEMEM_VMEMMAP
DECLARE_BITMAP(subsection_map, SUBSECTIONS_PER_SECTION);
#endif
@@ -1987,7 +1986,7 @@ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
{
int idx = subsection_map_index(pfn);
- return test_bit(idx, READ_ONCE(ms->usage)->subsection_map);
+ return test_bit(idx, ms->usage->subsection_map);
}
#else
static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
@@ -2011,7 +2010,6 @@ 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;
/*
* Ensure the upper PAGE_SHIFT bits are clear in the
@@ -2025,19 +2023,13 @@ static inline int pfn_valid(unsigned long pfn)
if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
return 0;
ms = __pfn_to_section(pfn);
- rcu_read_lock();
- if (!valid_section(ms)) {
- rcu_read_unlock();
+ if (!valid_section(ms))
return 0;
- }
/*
* Traditionally early sections always returned pfn_valid() for
* the entire section-sized span.
*/
- ret = early_section(ms) || pfn_section_valid(ms, pfn);
- rcu_read_unlock();
-
- return ret;
+ return early_section(ms) || pfn_section_valid(ms, pfn);
}
#endif
diff --git a/mm/sparse.c b/mm/sparse.c
index 338cf946dee8..77d91e565045 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -791,13 +791,6 @@ 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
@@ -806,10 +799,16 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
* was allocated during boot.
*/
if (!PageReserved(virt_to_page(ms->usage))) {
- kfree_rcu(ms->usage, rcu);
- WRITE_ONCE(ms->usage, NULL);
+ kfree(ms->usage);
+ 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;
}
/*
--
2.43.0
|