diff options
Diffstat (limited to 'mm/percpu.c')
-rw-r--r-- | mm/percpu.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index 1aa5d8fbca12..bf1bf1f4a729 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -110,9 +110,21 @@ static size_t pcpu_chunk_struct_size __read_mostly; | |||
110 | void *pcpu_base_addr __read_mostly; | 110 | void *pcpu_base_addr __read_mostly; |
111 | EXPORT_SYMBOL_GPL(pcpu_base_addr); | 111 | EXPORT_SYMBOL_GPL(pcpu_base_addr); |
112 | 112 | ||
113 | /* optional reserved chunk, only accessible for reserved allocations */ | 113 | /* |
114 | * The first chunk which always exists. Note that unlike other | ||
115 | * chunks, this one can be allocated and mapped in several different | ||
116 | * ways and thus often doesn't live in the vmalloc area. | ||
117 | */ | ||
118 | static struct pcpu_chunk *pcpu_first_chunk; | ||
119 | |||
120 | /* | ||
121 | * Optional reserved chunk. This chunk reserves part of the first | ||
122 | * chunk and serves it for reserved allocations. The amount of | ||
123 | * reserved offset is in pcpu_reserved_chunk_limit. When reserved | ||
124 | * area doesn't exist, the following variables contain NULL and 0 | ||
125 | * respectively. | ||
126 | */ | ||
114 | static struct pcpu_chunk *pcpu_reserved_chunk; | 127 | static struct pcpu_chunk *pcpu_reserved_chunk; |
115 | /* offset limit of the reserved chunk */ | ||
116 | static int pcpu_reserved_chunk_limit; | 128 | static int pcpu_reserved_chunk_limit; |
117 | 129 | ||
118 | /* | 130 | /* |
@@ -297,15 +309,16 @@ static struct rb_node **pcpu_chunk_rb_search(void *addr, | |||
297 | */ | 309 | */ |
298 | static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr) | 310 | static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr) |
299 | { | 311 | { |
312 | void *first_start = pcpu_first_chunk->vm->addr; | ||
300 | struct rb_node *n, *parent; | 313 | struct rb_node *n, *parent; |
301 | struct pcpu_chunk *chunk; | 314 | struct pcpu_chunk *chunk; |
302 | 315 | ||
303 | /* is it in the reserved chunk? */ | 316 | /* is it in the first chunk? */ |
304 | if (pcpu_reserved_chunk) { | 317 | if (addr >= first_start && addr < first_start + pcpu_chunk_size) { |
305 | void *start = pcpu_reserved_chunk->vm->addr; | 318 | /* is it in the reserved area? */ |
306 | 319 | if (addr < first_start + pcpu_reserved_chunk_limit) | |
307 | if (addr >= start && addr < start + pcpu_reserved_chunk_limit) | ||
308 | return pcpu_reserved_chunk; | 320 | return pcpu_reserved_chunk; |
321 | return pcpu_first_chunk; | ||
309 | } | 322 | } |
310 | 323 | ||
311 | /* nah... search the regular ones */ | 324 | /* nah... search the regular ones */ |
@@ -1147,7 +1160,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1147 | 1160 | ||
1148 | if (reserved_size) { | 1161 | if (reserved_size) { |
1149 | schunk->free_size = reserved_size; | 1162 | schunk->free_size = reserved_size; |
1150 | pcpu_reserved_chunk = schunk; /* not for dynamic alloc */ | 1163 | pcpu_reserved_chunk = schunk; |
1164 | pcpu_reserved_chunk_limit = static_size + reserved_size; | ||
1151 | } else { | 1165 | } else { |
1152 | schunk->free_size = dyn_size; | 1166 | schunk->free_size = dyn_size; |
1153 | dyn_size = 0; /* dynamic area covered */ | 1167 | dyn_size = 0; /* dynamic area covered */ |
@@ -1158,8 +1172,6 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1158 | if (schunk->free_size) | 1172 | if (schunk->free_size) |
1159 | schunk->map[schunk->map_used++] = schunk->free_size; | 1173 | schunk->map[schunk->map_used++] = schunk->free_size; |
1160 | 1174 | ||
1161 | pcpu_reserved_chunk_limit = static_size + schunk->free_size; | ||
1162 | |||
1163 | /* init dynamic chunk if necessary */ | 1175 | /* init dynamic chunk if necessary */ |
1164 | if (dyn_size) { | 1176 | if (dyn_size) { |
1165 | dchunk = alloc_bootmem(sizeof(struct pcpu_chunk)); | 1177 | dchunk = alloc_bootmem(sizeof(struct pcpu_chunk)); |
@@ -1226,13 +1238,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1226 | } | 1238 | } |
1227 | 1239 | ||
1228 | /* link the first chunk in */ | 1240 | /* link the first chunk in */ |
1229 | if (!dchunk) { | 1241 | pcpu_first_chunk = dchunk ?: schunk; |
1230 | pcpu_chunk_relocate(schunk, -1); | 1242 | pcpu_chunk_relocate(pcpu_first_chunk, -1); |
1231 | pcpu_chunk_addr_insert(schunk); | ||
1232 | } else { | ||
1233 | pcpu_chunk_relocate(dchunk, -1); | ||
1234 | pcpu_chunk_addr_insert(dchunk); | ||
1235 | } | ||
1236 | 1243 | ||
1237 | /* we're done */ | 1244 | /* we're done */ |
1238 | pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); | 1245 | pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); |