diff options
| author | Tejun Heo <tj@kernel.org> | 2009-08-14 02:00:52 -0400 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2009-08-14 02:00:52 -0400 |
| commit | 6563297ceafab6bbcc931b52e2a9e660fbb21fb2 (patch) | |
| tree | bcd5593a9b3088f609adc26185b179ff22b45535 | |
| parent | ca23e405e06d5fffb005df004c72781f76062f51 (diff) | |
percpu: use group information to allocate vmap areas sparsely
ai->groups[] contains which units need to be put consecutively and at
what offset from the chunk base address. Compile this information
into pcpu_group_offsets[] and pcpu_group_sizes[] in
pcpu_setup_first_chunk() and use them to allocate sparse vm areas
using pcpu_get_vm_areas().
This will be used to allow directly using sparse NUMA memories as
percpu areas.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Nick Piggin <npiggin@suse.de>
| -rw-r--r-- | mm/percpu.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index 548624309f83..cc9c4c64606d 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
| @@ -98,7 +98,7 @@ struct pcpu_chunk { | |||
| 98 | int map_used; /* # of map entries used */ | 98 | int map_used; /* # of map entries used */ |
| 99 | int map_alloc; /* # of map entries allocated */ | 99 | int map_alloc; /* # of map entries allocated */ |
| 100 | int *map; /* allocation map */ | 100 | int *map; /* allocation map */ |
| 101 | struct vm_struct *vm; /* mapped vmalloc region */ | 101 | struct vm_struct **vms; /* mapped vmalloc regions */ |
| 102 | bool immutable; /* no [de]population allowed */ | 102 | bool immutable; /* no [de]population allowed */ |
| 103 | unsigned long populated[]; /* populated bitmap */ | 103 | unsigned long populated[]; /* populated bitmap */ |
| 104 | }; | 104 | }; |
| @@ -106,7 +106,7 @@ struct pcpu_chunk { | |||
| 106 | static int pcpu_unit_pages __read_mostly; | 106 | static int pcpu_unit_pages __read_mostly; |
| 107 | static int pcpu_unit_size __read_mostly; | 107 | static int pcpu_unit_size __read_mostly; |
| 108 | static int pcpu_nr_units __read_mostly; | 108 | static int pcpu_nr_units __read_mostly; |
| 109 | static int pcpu_chunk_size __read_mostly; | 109 | static int pcpu_atom_size __read_mostly; |
| 110 | static int pcpu_nr_slots __read_mostly; | 110 | static int pcpu_nr_slots __read_mostly; |
| 111 | static size_t pcpu_chunk_struct_size __read_mostly; | 111 | static size_t pcpu_chunk_struct_size __read_mostly; |
| 112 | 112 | ||
| @@ -121,6 +121,11 @@ EXPORT_SYMBOL_GPL(pcpu_base_addr); | |||
| 121 | static const int *pcpu_unit_map __read_mostly; /* cpu -> unit */ | 121 | static const int *pcpu_unit_map __read_mostly; /* cpu -> unit */ |
| 122 | const unsigned long *pcpu_unit_offsets __read_mostly; /* cpu -> unit offset */ | 122 | const unsigned long *pcpu_unit_offsets __read_mostly; /* cpu -> unit offset */ |
| 123 | 123 | ||
| 124 | /* group information, used for vm allocation */ | ||
| 125 | static int pcpu_nr_groups __read_mostly; | ||
| 126 | static const unsigned long *pcpu_group_offsets __read_mostly; | ||
| 127 | static const size_t *pcpu_group_sizes __read_mostly; | ||
| 128 | |||
| 124 | /* | 129 | /* |
| 125 | * The first chunk which always exists. Note that unlike other | 130 | * The first chunk which always exists. Note that unlike other |
| 126 | * chunks, this one can be allocated and mapped in several different | 131 | * chunks, this one can be allocated and mapped in several different |
| @@ -988,8 +993,8 @@ static void free_pcpu_chunk(struct pcpu_chunk *chunk) | |||
| 988 | { | 993 | { |
| 989 | if (!chunk) | 994 | if (!chunk) |
| 990 | return; | 995 | return; |
| 991 | if (chunk->vm) | 996 | if (chunk->vms) |
| 992 | free_vm_area(chunk->vm); | 997 | pcpu_free_vm_areas(chunk->vms, pcpu_nr_groups); |
| 993 | pcpu_mem_free(chunk->map, chunk->map_alloc * sizeof(chunk->map[0])); | 998 | pcpu_mem_free(chunk->map, chunk->map_alloc * sizeof(chunk->map[0])); |
| 994 | kfree(chunk); | 999 | kfree(chunk); |
| 995 | } | 1000 | } |
| @@ -1006,8 +1011,10 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void) | |||
| 1006 | chunk->map_alloc = PCPU_DFL_MAP_ALLOC; | 1011 | chunk->map_alloc = PCPU_DFL_MAP_ALLOC; |
| 1007 | chunk->map[chunk->map_used++] = pcpu_unit_size; | 1012 | chunk->map[chunk->map_used++] = pcpu_unit_size; |
| 1008 | 1013 | ||
| 1009 | chunk->vm = get_vm_area(pcpu_chunk_size, VM_ALLOC); | 1014 | chunk->vms = pcpu_get_vm_areas(pcpu_group_offsets, pcpu_group_sizes, |
| 1010 | if (!chunk->vm) { | 1015 | pcpu_nr_groups, pcpu_atom_size, |
| 1016 | GFP_KERNEL); | ||
| 1017 | if (!chunk->vms) { | ||
| 1011 | free_pcpu_chunk(chunk); | 1018 | free_pcpu_chunk(chunk); |
| 1012 | return NULL; | 1019 | return NULL; |
| 1013 | } | 1020 | } |
| @@ -1015,7 +1022,7 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void) | |||
| 1015 | INIT_LIST_HEAD(&chunk->list); | 1022 | INIT_LIST_HEAD(&chunk->list); |
| 1016 | chunk->free_size = pcpu_unit_size; | 1023 | chunk->free_size = pcpu_unit_size; |
| 1017 | chunk->contig_hint = pcpu_unit_size; | 1024 | chunk->contig_hint = pcpu_unit_size; |
| 1018 | chunk->base_addr = chunk->vm->addr; | 1025 | chunk->base_addr = chunk->vms[0]->addr - pcpu_group_offsets[0]; |
| 1019 | 1026 | ||
| 1020 | return chunk; | 1027 | return chunk; |
| 1021 | } | 1028 | } |
| @@ -1571,6 +1578,8 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, | |||
| 1571 | size_t dyn_size = ai->dyn_size; | 1578 | size_t dyn_size = ai->dyn_size; |
| 1572 | size_t size_sum = ai->static_size + ai->reserved_size + dyn_size; | 1579 | size_t size_sum = ai->static_size + ai->reserved_size + dyn_size; |
| 1573 | struct pcpu_chunk *schunk, *dchunk = NULL; | 1580 | struct pcpu_chunk *schunk, *dchunk = NULL; |
| 1581 | unsigned long *group_offsets; | ||
| 1582 | size_t *group_sizes; | ||
| 1574 | unsigned long *unit_off; | 1583 | unsigned long *unit_off; |
| 1575 | unsigned int cpu; | 1584 | unsigned int cpu; |
| 1576 | int *unit_map; | 1585 | int *unit_map; |
| @@ -1588,7 +1597,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, | |||
| 1588 | 1597 | ||
| 1589 | pcpu_dump_alloc_info(KERN_DEBUG, ai); | 1598 | pcpu_dump_alloc_info(KERN_DEBUG, ai); |
| 1590 | 1599 | ||
| 1591 | /* determine number of units and initialize unit_map and base */ | 1600 | /* process group information and build config tables accordingly */ |
| 1601 | group_offsets = alloc_bootmem(ai->nr_groups * sizeof(group_offsets[0])); | ||
| 1602 | group_sizes = alloc_bootmem(ai->nr_groups * sizeof(group_sizes[0])); | ||
| 1592 | unit_map = alloc_bootmem(nr_cpu_ids * sizeof(unit_map[0])); | 1603 | unit_map = alloc_bootmem(nr_cpu_ids * sizeof(unit_map[0])); |
| 1593 | unit_off = alloc_bootmem(nr_cpu_ids * sizeof(unit_off[0])); | 1604 | unit_off = alloc_bootmem(nr_cpu_ids * sizeof(unit_off[0])); |
| 1594 | 1605 | ||
| @@ -1599,6 +1610,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, | |||
| 1599 | for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) { | 1610 | for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) { |
| 1600 | const struct pcpu_group_info *gi = &ai->groups[group]; | 1611 | const struct pcpu_group_info *gi = &ai->groups[group]; |
| 1601 | 1612 | ||
| 1613 | group_offsets[group] = gi->base_offset; | ||
| 1614 | group_sizes[group] = gi->nr_units * ai->unit_size; | ||
| 1615 | |||
| 1602 | for (i = 0; i < gi->nr_units; i++) { | 1616 | for (i = 0; i < gi->nr_units; i++) { |
| 1603 | cpu = gi->cpu_map[i]; | 1617 | cpu = gi->cpu_map[i]; |
| 1604 | if (cpu == NR_CPUS) | 1618 | if (cpu == NR_CPUS) |
| @@ -1620,13 +1634,16 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, | |||
| 1620 | for_each_possible_cpu(cpu) | 1634 | for_each_possible_cpu(cpu) |
| 1621 | BUG_ON(unit_map[cpu] == NR_CPUS); | 1635 | BUG_ON(unit_map[cpu] == NR_CPUS); |
| 1622 | 1636 | ||
| 1637 | pcpu_nr_groups = ai->nr_groups; | ||
| 1638 | pcpu_group_offsets = group_offsets; | ||
| 1639 | pcpu_group_sizes = group_sizes; | ||
| 1623 | pcpu_unit_map = unit_map; | 1640 | pcpu_unit_map = unit_map; |
| 1624 | pcpu_unit_offsets = unit_off; | 1641 | pcpu_unit_offsets = unit_off; |
| 1625 | 1642 | ||
| 1626 | /* determine basic parameters */ | 1643 | /* determine basic parameters */ |
| 1627 | pcpu_unit_pages = ai->unit_size >> PAGE_SHIFT; | 1644 | pcpu_unit_pages = ai->unit_size >> PAGE_SHIFT; |
| 1628 | pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; | 1645 | pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; |
| 1629 | pcpu_chunk_size = pcpu_nr_units * pcpu_unit_size; | 1646 | pcpu_atom_size = ai->atom_size; |
| 1630 | pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) + | 1647 | pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) + |
| 1631 | BITS_TO_LONGS(pcpu_unit_pages) * sizeof(unsigned long); | 1648 | BITS_TO_LONGS(pcpu_unit_pages) * sizeof(unsigned long); |
| 1632 | 1649 | ||
