FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
linux/mm/sparse-vmemmap.c at master · fabgithub/linux · GitHub
fabgithub
linux
Repository navigation
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
linux
/
mm
/
sparse-vmemmap.c
Copy path
More file actions
More file actions
Latest commit
History
History
History
233 lines (203 loc) · 5.91 KB
Breadcrumbs
linux
/
mm
/
sparse-vmemmap.c
Copy path
File metadata and controls
233 lines (203 loc) · 5.91 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
* Virtual Memory Map support
*
* (C) 2007 sgi. Christoph Lameter.
*
* Virtual memory maps allow VM primitives pfn_to_page, page_to_pfn,
* virt_to_page, page_address() to be implemented as a base offset
* calculation without memory access.
*
* However, virtual mappings need a page table and TLBs. Many Linux
* architectures already map their physical space using 1-1 mappings
* via TLBs. For those arches the virtual memory map is essentially
* for free if we use the same page size as the 1-1 mappings. In that
* case the overhead consists of a few additional pages that are
* allocated to create a view of memory for vmemmap.
*
* The architecture is expected to provide a vmemmap_populate() function
* to instantiate the mapping.
*/
#include
<linux/mm.h>
#include
<linux/mmzone.h>
#include
<linux/bootmem.h>
#include
<linux/highmem.h>
#include
<linux/slab.h>
#include
<linux/spinlock.h>
#include
<linux/vmalloc.h>
#include
<linux/sched.h>
#include
<asm/dma.h>
#include
<asm/pgalloc.h>
#include
<asm/pgtable.h>
/*
* Allocate a block of memory to be used to back the virtual memory map
* or to back the page tables that are used to create the mapping.
* Uses the main allocators if they are available, else bootmem.
*/
static
void
*
__init_refok
__earlyonly_bootmem_alloc
(
int
node
,
unsigned long
size
,
unsigned long
align
,
unsigned long
goal
)
{
return
__alloc_bootmem_node_high
(
NODE_DATA
(
node
),
size
,
align
,
goal
);
}
static
void
*
vmemmap_buf
;
static
void
*
vmemmap_buf_end
;
void
*
__meminit
vmemmap_alloc_block
(
unsigned long
size
,
int
node
)
{
/* If the main allocator is up use that, fallback to bootmem. */
if
(
slab_is_available
()) {
struct
page
*
page
;
if
(
node_state
(
node
,
N_HIGH_MEMORY
))
page
=
alloc_pages_node
(
node
,
GFP_KERNEL
|
__GFP_ZERO
|
__GFP_REPEAT
,
get_order
(
size
));
else
page
=
alloc_pages
(
GFP_KERNEL
|
__GFP_ZERO
|
__GFP_REPEAT
,
get_order
(
size
));
if
(
page
)
return
page_address
(
page
);
return
NULL
;
}
else
return
__earlyonly_bootmem_alloc
(
node
,
size
,
size
,
__pa
(
MAX_DMA_ADDRESS
));
}
/* need to make sure size is all the same during early stage */
void
*
__meminit
vmemmap_alloc_block_buf
(
unsigned long
size
,
int
node
)
{
void
*
ptr
;
if
(!
vmemmap_buf
)
return
vmemmap_alloc_block
(
size
,
node
);
/* take the from buf */
ptr
=
(
void
*
)
ALIGN
((
unsigned long
)
vmemmap_buf
,
size
);
if
(
ptr
+
size
>
vmemmap_buf_end
)
return
vmemmap_alloc_block
(
size
,
node
);
vmemmap_buf
=
ptr
+
size
;
return
ptr
;
}
void
__meminit
vmemmap_verify
(
pte_t
*
pte
,
int
node
,
unsigned long
start
,
unsigned long
end
)
{
unsigned long
pfn
=
pte_pfn
(
*
pte
);
int
actual_node
=
early_pfn_to_nid
(
pfn
);
if
(
node_distance
(
actual_node
,
node
)
>
LOCAL_DISTANCE
)
printk
(
KERN_WARNING
"[%lx-%lx] potential offnode "
"page_structs\n"
,
start
,
end
-
1
);
}
pte_t
*
__meminit
vmemmap_pte_populate
(
pmd_t
*
pmd
,
unsigned
long
addr
,
int
node
)
{
pte_t
*
pte
=
pte_offset_kernel
(
pmd
,
addr
);
if
(
pte_none
(
*
pte
)) {
pte_t
entry
;
void
*
p
=
vmemmap_alloc_block_buf
(
PAGE_SIZE
,
node
);
if
(!
p
)
return
NULL
;
entry
=
pfn_pte
(
__pa
(
p
) >>
PAGE_SHIFT
,
PAGE_KERNEL
);
set_pte_at
(
&
init_mm
,
addr
,
pte
,
entry
);
}
return
pte
;
}
pmd_t
*
__meminit
vmemmap_pmd_populate
(
pud_t
*
pud
,
unsigned
long
addr
,
int
node
)
{
pmd_t
*
pmd
=
pmd_offset
(
pud
,
addr
);
if
(
pmd_none
(
*
pmd
)) {
void
*
p
=
vmemmap_alloc_block
(
PAGE_SIZE
,
node
);
if
(!
p
)
return
NULL
;
pmd_populate_kernel
(
&
init_mm
,
pmd
,
p
);
}
return
pmd
;
}
pud_t
*
__meminit
vmemmap_pud_populate
(
pgd_t
*
pgd
,
unsigned
long
addr
,
int
node
)
{
pud_t
*
pud
=
pud_offset
(
pgd
,
addr
);
if
(
pud_none
(
*
pud
)) {
void
*
p
=
vmemmap_alloc_block
(
PAGE_SIZE
,
node
);
if
(!
p
)
return
NULL
;
pud_populate
(
&
init_mm
,
pud
,
p
);
}
return
pud
;
}
pgd_t
*
__meminit
vmemmap_pgd_populate
(
unsigned
long
addr
,
int
node
)
{
pgd_t
*
pgd
=
pgd_offset_k
(
addr
);
if
(
pgd_none
(
*
pgd
)) {
void
*
p
=
vmemmap_alloc_block
(
PAGE_SIZE
,
node
);
if
(!
p
)
return
NULL
;
pgd_populate
(
&
init_mm
,
pgd
,
p
);
}
return
pgd
;
}
int
__meminit
vmemmap_populate_basepages
(
unsigned long
start
,
unsigned long
end
,
int
node
)
{
unsigned long
addr
=
start
;
pgd_t
*
pgd
;
pud_t
*
pud
;
pmd_t
*
pmd
;
pte_t
*
pte
;
for
(;
addr
<
end
;
addr
+=
PAGE_SIZE
) {
pgd
=
vmemmap_pgd_populate
(
addr
,
node
);
if
(!
pgd
)
return
-
ENOMEM
;
pud
=
vmemmap_pud_populate
(
pgd
,
addr
,
node
);
if
(!
pud
)
return
-
ENOMEM
;
pmd
=
vmemmap_pmd_populate
(
pud
,
addr
,
node
);
if
(!
pmd
)
return
-
ENOMEM
;
pte
=
vmemmap_pte_populate
(
pmd
,
addr
,
node
);
if
(!
pte
)
return
-
ENOMEM
;
vmemmap_verify
(
pte
,
node
,
addr
,
addr
+
PAGE_SIZE
);
}
return
0
;
}
struct
page
*
__meminit
sparse_mem_map_populate
(
unsigned long
pnum
,
int
nid
)
{
unsigned long
start
;
unsigned long
end
;
struct
page
*
map
;
map
=
pfn_to_page
(
pnum
*
PAGES_PER_SECTION
);
start
=
(
unsigned long
)
map
;
end
=
(
unsigned long
)(
map
+
PAGES_PER_SECTION
);
if
(
vmemmap_populate
(
start
,
end
,
nid
))
return
NULL
;
return
map
;
}
void
__init
sparse_mem_maps_populate_node
(
struct
page
*
*
map_map
,
unsigned long
pnum_begin
,
unsigned long
pnum_end
,
unsigned long
map_count
,
int
nodeid
)
{
unsigned long
pnum
;
unsigned long
size
=
sizeof
(
struct
page
)
*
PAGES_PER_SECTION
;
void
*
vmemmap_buf_start
;
size
=
ALIGN
(
size
,
PMD_SIZE
);
vmemmap_buf_start
=
__earlyonly_bootmem_alloc
(
nodeid
,
size
*
map_count
,
PMD_SIZE
,
__pa
(
MAX_DMA_ADDRESS
));
if
(
vmemmap_buf_start
) {
vmemmap_buf
=
vmemmap_buf_start
;
vmemmap_buf_end
=
vmemmap_buf_start
+
size
*
map_count
;
}
for
(
pnum
=
pnum_begin
;
pnum
<
pnum_end
;
pnum
++
) {
struct
mem_section
*
ms
;
if
(!
present_section_nr
(
pnum
))
continue
;
map_map
[
pnum
]
=
sparse_mem_map_populate
(
pnum
,
nodeid
);
if
(
map_map
[
pnum
])
continue
;
ms
=
__nr_to_section
(
pnum
);
printk
(
KERN_ERR
"%s: sparsemem memory map backing failed "
"some memory will not be available.\n"
,
__func__
);
ms
->
section_mem_map
=
0
;
}
if
(
vmemmap_buf_start
) {
/* need to free left buf */
free_bootmem
(
__pa
(
vmemmap_buf
),
vmemmap_buf_end
-
vmemmap_buf
);
vmemmap_buf
=
NULL
;
vmemmap_buf_end
=
NULL
;
}
}
Back
|
FazBrowse Home
|
New Git URL