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 /mm/percpu.c | |
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>
Diffstat (limited to 'mm/percpu.c')
-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 | ||