Commit 9b5a4d4f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-3.2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu

* 'for-3.2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu:
  percpu: explain why per_cpu_ptr_to_phys() is more complicated than necessary
  percpu: fix chunk range calculation
  percpu: rename pcpu_mem_alloc to pcpu_mem_zalloc
parents cb359992 67589c71
...@@ -50,14 +50,13 @@ static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk, ...@@ -50,14 +50,13 @@ static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk,
if (!pages || !bitmap) { if (!pages || !bitmap) {
if (may_alloc && !pages) if (may_alloc && !pages)
pages = pcpu_mem_alloc(pages_size); pages = pcpu_mem_zalloc(pages_size);
if (may_alloc && !bitmap) if (may_alloc && !bitmap)
bitmap = pcpu_mem_alloc(bitmap_size); bitmap = pcpu_mem_zalloc(bitmap_size);
if (!pages || !bitmap) if (!pages || !bitmap)
return NULL; return NULL;
} }
memset(pages, 0, pages_size);
bitmap_copy(bitmap, chunk->populated, pcpu_unit_pages); bitmap_copy(bitmap, chunk->populated, pcpu_unit_pages);
*bitmapp = bitmap; *bitmapp = bitmap;
...@@ -143,8 +142,8 @@ static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk, ...@@ -143,8 +142,8 @@ static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk,
int page_start, int page_end) int page_start, int page_end)
{ {
flush_cache_vunmap( flush_cache_vunmap(
pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
} }
static void __pcpu_unmap_pages(unsigned long addr, int nr_pages) static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
...@@ -206,8 +205,8 @@ static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk, ...@@ -206,8 +205,8 @@ static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk,
int page_start, int page_end) int page_start, int page_end)
{ {
flush_tlb_kernel_range( flush_tlb_kernel_range(
pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
} }
static int __pcpu_map_pages(unsigned long addr, struct page **pages, static int __pcpu_map_pages(unsigned long addr, struct page **pages,
...@@ -284,8 +283,8 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk, ...@@ -284,8 +283,8 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
int page_start, int page_end) int page_start, int page_end)
{ {
flush_cache_vmap( flush_cache_vmap(
pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
} }
/** /**
......
...@@ -116,9 +116,9 @@ static int pcpu_atom_size __read_mostly; ...@@ -116,9 +116,9 @@ static int pcpu_atom_size __read_mostly;
static int pcpu_nr_slots __read_mostly; static int pcpu_nr_slots __read_mostly;
static size_t pcpu_chunk_struct_size __read_mostly; static size_t pcpu_chunk_struct_size __read_mostly;
/* cpus with the lowest and highest unit numbers */ /* cpus with the lowest and highest unit addresses */
static unsigned int pcpu_first_unit_cpu __read_mostly; static unsigned int pcpu_low_unit_cpu __read_mostly;
static unsigned int pcpu_last_unit_cpu __read_mostly; static unsigned int pcpu_high_unit_cpu __read_mostly;
/* the address of the first chunk which starts with the kernel static area */ /* the address of the first chunk which starts with the kernel static area */
void *pcpu_base_addr __read_mostly; void *pcpu_base_addr __read_mostly;
...@@ -273,11 +273,11 @@ static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk, ...@@ -273,11 +273,11 @@ static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk,
(rs) = (re) + 1, pcpu_next_pop((chunk), &(rs), &(re), (end))) (rs) = (re) + 1, pcpu_next_pop((chunk), &(rs), &(re), (end)))
/** /**
* pcpu_mem_alloc - allocate memory * pcpu_mem_zalloc - allocate memory
* @size: bytes to allocate * @size: bytes to allocate
* *
* Allocate @size bytes. If @size is smaller than PAGE_SIZE, * Allocate @size bytes. If @size is smaller than PAGE_SIZE,
* kzalloc() is used; otherwise, vmalloc() is used. The returned * kzalloc() is used; otherwise, vzalloc() is used. The returned
* memory is always zeroed. * memory is always zeroed.
* *
* CONTEXT: * CONTEXT:
...@@ -286,7 +286,7 @@ static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk, ...@@ -286,7 +286,7 @@ static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk,
* RETURNS: * RETURNS:
* Pointer to the allocated area on success, NULL on failure. * Pointer to the allocated area on success, NULL on failure.
*/ */
static void *pcpu_mem_alloc(size_t size) static void *pcpu_mem_zalloc(size_t size)
{ {
if (WARN_ON_ONCE(!slab_is_available())) if (WARN_ON_ONCE(!slab_is_available()))
return NULL; return NULL;
...@@ -302,7 +302,7 @@ static void *pcpu_mem_alloc(size_t size) ...@@ -302,7 +302,7 @@ static void *pcpu_mem_alloc(size_t size)
* @ptr: memory to free * @ptr: memory to free
* @size: size of the area * @size: size of the area
* *
* Free @ptr. @ptr should have been allocated using pcpu_mem_alloc(). * Free @ptr. @ptr should have been allocated using pcpu_mem_zalloc().
*/ */
static void pcpu_mem_free(void *ptr, size_t size) static void pcpu_mem_free(void *ptr, size_t size)
{ {
...@@ -384,7 +384,7 @@ static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc) ...@@ -384,7 +384,7 @@ static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc)
size_t old_size = 0, new_size = new_alloc * sizeof(new[0]); size_t old_size = 0, new_size = new_alloc * sizeof(new[0]);
unsigned long flags; unsigned long flags;
new = pcpu_mem_alloc(new_size); new = pcpu_mem_zalloc(new_size);
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
...@@ -604,11 +604,12 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void) ...@@ -604,11 +604,12 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
{ {
struct pcpu_chunk *chunk; struct pcpu_chunk *chunk;
chunk = pcpu_mem_alloc(pcpu_chunk_struct_size); chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size);
if (!chunk) if (!chunk)
return NULL; return NULL;
chunk->map = pcpu_mem_alloc(PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0])); chunk->map = pcpu_mem_zalloc(PCPU_DFL_MAP_ALLOC *
sizeof(chunk->map[0]));
if (!chunk->map) { if (!chunk->map) {
kfree(chunk); kfree(chunk);
return NULL; return NULL;
...@@ -977,6 +978,17 @@ bool is_kernel_percpu_address(unsigned long addr) ...@@ -977,6 +978,17 @@ bool is_kernel_percpu_address(unsigned long addr)
* address. The caller is responsible for ensuring @addr stays valid * address. The caller is responsible for ensuring @addr stays valid
* until this function finishes. * until this function finishes.
* *
* percpu allocator has special setup for the first chunk, which currently
* supports either embedding in linear address space or vmalloc mapping,
* and, from the second one, the backing allocator (currently either vm or
* km) provides translation.
*
* The addr can be tranlated simply without checking if it falls into the
* first chunk. But the current code reflects better how percpu allocator
* actually works, and the verification can discover both bugs in percpu
* allocator itself and per_cpu_ptr_to_phys() callers. So we keep current
* code.
*
* RETURNS: * RETURNS:
* The physical address for @addr. * The physical address for @addr.
*/ */
...@@ -984,19 +996,19 @@ phys_addr_t per_cpu_ptr_to_phys(void *addr) ...@@ -984,19 +996,19 @@ phys_addr_t per_cpu_ptr_to_phys(void *addr)
{ {
void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr); void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr);
bool in_first_chunk = false; bool in_first_chunk = false;
unsigned long first_start, first_end; unsigned long first_low, first_high;
unsigned int cpu; unsigned int cpu;
/* /*
* The following test on first_start/end isn't strictly * The following test on unit_low/high isn't strictly
* necessary but will speed up lookups of addresses which * necessary but will speed up lookups of addresses which
* aren't in the first chunk. * aren't in the first chunk.
*/ */
first_start = pcpu_chunk_addr(pcpu_first_chunk, pcpu_first_unit_cpu, 0); first_low = pcpu_chunk_addr(pcpu_first_chunk, pcpu_low_unit_cpu, 0);
first_end = pcpu_chunk_addr(pcpu_first_chunk, pcpu_last_unit_cpu, first_high = pcpu_chunk_addr(pcpu_first_chunk, pcpu_high_unit_cpu,
pcpu_unit_pages); pcpu_unit_pages);
if ((unsigned long)addr >= first_start && if ((unsigned long)addr >= first_low &&
(unsigned long)addr < first_end) { (unsigned long)addr < first_high) {
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
void *start = per_cpu_ptr(base, cpu); void *start = per_cpu_ptr(base, cpu);
...@@ -1233,7 +1245,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, ...@@ -1233,7 +1245,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
for (cpu = 0; cpu < nr_cpu_ids; cpu++) for (cpu = 0; cpu < nr_cpu_ids; cpu++)
unit_map[cpu] = UINT_MAX; unit_map[cpu] = UINT_MAX;
pcpu_first_unit_cpu = NR_CPUS;
pcpu_low_unit_cpu = NR_CPUS;
pcpu_high_unit_cpu = NR_CPUS;
for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) { for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) {
const struct pcpu_group_info *gi = &ai->groups[group]; const struct pcpu_group_info *gi = &ai->groups[group];
...@@ -1253,9 +1267,13 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, ...@@ -1253,9 +1267,13 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
unit_map[cpu] = unit + i; unit_map[cpu] = unit + i;
unit_off[cpu] = gi->base_offset + i * ai->unit_size; unit_off[cpu] = gi->base_offset + i * ai->unit_size;
if (pcpu_first_unit_cpu == NR_CPUS) /* determine low/high unit_cpu */
pcpu_first_unit_cpu = cpu; if (pcpu_low_unit_cpu == NR_CPUS ||
pcpu_last_unit_cpu = cpu; unit_off[cpu] < unit_off[pcpu_low_unit_cpu])
pcpu_low_unit_cpu = cpu;
if (pcpu_high_unit_cpu == NR_CPUS ||
unit_off[cpu] > unit_off[pcpu_high_unit_cpu])
pcpu_high_unit_cpu = cpu;
} }
} }
pcpu_nr_units = unit; pcpu_nr_units = unit;
...@@ -1889,7 +1907,7 @@ void __init percpu_init_late(void) ...@@ -1889,7 +1907,7 @@ void __init percpu_init_late(void)
BUILD_BUG_ON(size > PAGE_SIZE); BUILD_BUG_ON(size > PAGE_SIZE);
map = pcpu_mem_alloc(size); map = pcpu_mem_zalloc(size);
BUG_ON(!map); BUG_ON(!map);
spin_lock_irqsave(&pcpu_lock, flags); spin_lock_irqsave(&pcpu_lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment