Chinaunix首页 | 论坛 | 博客
  • 博客访问: 437300
  • 博文数量: 123
  • 博客积分: 2686
  • 博客等级: 少校
  • 技术积分: 1349
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-23 22:11
文章分类
文章存档

2012年(3)

2011年(10)

2010年(100)

2009年(10)

我的朋友

分类: LINUX

2010-10-16 17:40:21

[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.















阅读(1384) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~