[start_kernel() -> setup_arch() -> paging_init() ->
zone_sizes_init() -> free_area_init_nodes()]
free_area_init_nodes - Initialise all pg_data_t and zone data @max_zone_pfn: an array of max PFNs for each zone. This will call free_area_init_node() for each active node in the system. Using the page ranges provided by add_active_range(), the size of each zone in each node and their holes is calculated.
If the maximum PFN between two adjacent zones match, it is assumed that the zone is empty. For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed that arch_max_dma32_pfn has no pages. It is also assumed that a zone starts where the previous one ended. For example, ZONE_DMA32 starts at arch_max_dma_pfn. void __init free_area_init_nodes(unsigned long *max_zone_pfn)
{
unsigned long nid;
int i;
/* Sort early_node_map as initialisation assumes it is sorted */
sort_node_map();//see below comment 1
//see below comment 2
/* Record where the zone boundaries are */
memset(arch_zone_lowest_possible_pfn, 0,
sizeof(arch_zone_lowest_possible_pfn));
memset(arch_zone_highest_possible_pfn, 0,
sizeof(arch_zone_highest_possible_pfn));
arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
for (i = 1; i < MAX_NR_ZONES; i++) {
if (i == ZONE_MOVABLE)
continue;
arch_zone_lowest_possible_pfn[i] =
arch_zone_highest_possible_pfn[i-1];
arch_zone_highest_possible_pfn[i] =
max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);
}
arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;
arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;
/* Find the PFNs that ZONE_MOVABLE begins at in each node */
//see Comment 3
memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn));
find_zone_movable_pfns_for_nodes(zone_movable_pfn);
/* Print out the zone ranges, Printed message can be see using dmesg |less */
printk("Zone PFN ranges:\n");
for (i = 0; i < MAX_NR_ZONES; i++) {
if (i == ZONE_MOVABLE)
continue;
printk(" %-8s ", zone_names[i]);
if (arch_zone_lowest_possible_pfn[i] ==
arch_zone_highest_possible_pfn[i])
printk("empty\n");
else
printk("%0#10lx -> %0#10lx\n",
arch_zone_lowest_possible_pfn[i],
arch_zone_highest_possible_pfn[i]);
}
/* Print out the PFNs ZONE_MOVABLE begins at in each node */
printk("Movable zone start PFN for each node\n");
for (i = 0; i < MAX_NUMNODES; i++) {
if (zone_movable_pfn[i])
printk(" Node %d: %lu\n", i, zone_movable_pfn[i]);
}
/* Print out the early_node_map[], see comment 4*/
printk("early_node_map[%d] active PFN ranges\n", nr_nodemap_entries);
for (i = 0; i < nr_nodemap_entries; i++)
printk(" %3d: %0#10lx -> %0#10lx\n", early_node_map[i].nid,
early_node_map[i].start_pfn,
early_node_map[i].end_pfn);
/* Initialise every node */
mminit_verify_pageflags_layout();
setup_nr_node_ids();
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
free_area_init_node(nid, NULL,
find_min_pfn_for_node(nid), NULL);//see below comment 5
/* Any memory on that node */
if (pgdat->node_present_pages)
node_set_state(nid, N_HIGH_MEMORY);
check_for_regular_memory(pgdat);//see comment 6
}
}
|
Comment 1:early_node_map and
nr_nodemap_entries are both global variables defined in page_alloc.c:
static struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS];static int __meminitdata nr_nodemap_entries;struct node_active_region { unsigned long start_pfn; unsigned long end_pfn; int nid;};/* sort the node_map by start_pfn */
void __init sort_node_map(void)
{
sort(early_node_map, (size_t)nr_nodemap_entries,
sizeof(struct node_active_region),
cmp_node_active_region, NULL);
}
|
Comment 2:
arch_zone_lowest_possible_pfn and
arch_zone_highest_possible_pfn are both global variables defined in page_alloc.c
, they record the lowest and highest page frame number of each zone type.
static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];find_min_pfn_with_active_regions is used to find the smallest registered usable page frame for the lowest registered zone.
Comment 3:zone_movable_pfn is a global array defined in alloc_page.c:
static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];Since
ZONE_MOVABLE is a virtual zone and not associated with real hardware zones, the zone boundaries are always set to zero.
The movable zone for each node starts above a certain page frame number of a specific zone for each node. The corresponding numbers are computed in
find_zone_movable_pfns_for_nodes.It find the PFN the Movable zone begins in each node. Kernel memory is spread evenly between nodes as long as the nodes have enough
memory. When they don't, some nodes will have more kernelcore than others.
Comment 4:how is
early_node_map[] been initiated ?
Comment 5:
void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
unsigned long node_start_pfn, unsigned long *zholes_size)
{
pg_data_t *pgdat = NODE_DATA(nid);
pgdat->node_id = nid;
pgdat->node_start_pfn = node_start_pfn;
calculate_node_totalpages(pgdat, zones_size, zholes_size);
alloc_node_mem_map(pgdat);
#ifdef CONFIG_FLAT_NODE_MEM_MAP
printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n",
nid, (unsigned long)pgdat,
(unsigned long)pgdat->node_mem_map);
#endif
free_area_init_core(pgdat, zones_size, zholes_size);
}
|
Comment 6:check_for_regular_memory checks if pages in any zone below
ZONE_HIGHMEM are present and sets the flag
N_NORMAL_MEMORY in the node bitmap accordingly.
阅读(1388) | 评论(0) | 转发(0) |