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

2012年(3)

2011年(10)

2010年(100)

2009年(10)

我的朋友

分类: LINUX

2010-10-16 21:09:54

[start_kernel() -> setup_arch() -> paging_init() -> zone_sizes_init() -> free_area_init_nodes() -> free_area_init_node() -> alloc_node_mem_map()]

alloc_node_mem_map is responsible for initializing a simple but nevertheless very important data structure. As noted above, there is an instance of struct page for every physical memory page in the system. Initialization of this structure is performed by alloc_node_mem_map.

static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
{
    /* Skip empty nodes */
    if (!pgdat->node_spanned_pages)
        return;

#ifdef CONFIG_FLAT_NODE_MEM_MAP
    /* ia64 gets its own node_mem_map, before this, without bootmem */
    if (!pgdat->node_mem_map) {
        unsigned long size, start, end;
        struct page *map;

        /*
         * The zone's endpoints aren't required to be MAX_ORDER
         * aligned but the node_mem_map endpoints must be in order
         * for the buddy allocator to function correctly.
         */

        start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);
        end = pgdat->node_start_pfn + pgdat->node_spanned_pages;
        end = ALIGN(end, MAX_ORDER_NR_PAGES);
        size = (end - start) * sizeof(struct page);
        map = alloc_remap(pgdat->node_id, size);//see comment 1
        if (!map)
            map = alloc_bootmem_node(pgdat, size);
        pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
    }
#ifndef CONFIG_NEED_MULTIPLE_NODES
    /*
     * With no DISCONTIG, the global mem_map is just set as node 0's
     */

    //see Comment 2
    if (pgdat == NODE_DATA(0)) {
        mem_map = NODE_DATA(0)->node_mem_map;
#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
        if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
            mem_map -= (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
    }
#endif
#endif /* CONFIG_FLAT_NODE_MEM_MAP */
}



Comment 1:
/*
 * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel
 * virtual address space (KVA) is reserved and portions of nodes are mapped
 * using it. This is to allow node-local memory to be allocated for
 * structures that would normally require ZONE_NORMAL. The memory is
 * allocated with alloc_remap() and callers should be prepared to allocate
 * from the bootmem allocator instead.
 */
static unsigned long node_remap_start_pfn[MAX_NUMNODES];
static void *node_remap_end_vaddr[MAX_NUMNODES];
static void *node_remap_alloc_vaddr[MAX_NUMNODES];
static unsigned long node_remap_offset[MAX_NUMNODES];

node_remap_alloc_vaddr[] is initiated during [start_kernel() > setup_arch() > initmem_init() > init_remap_allocator()]
static void init_remap_allocator(int nid)
{
    node_remap_start_vaddr[nid] = pfn_to_kaddr(
            kva_start_pfn + node_remap_offset[nid]);
    node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] +
        (node_remap_size[nid] * PAGE_SIZE);
    node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] +
        ALIGN(sizeof(pg_data_t), PAGE_SIZE);

    printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid,
        (ulong) node_remap_start_vaddr[nid],
        (ulong) node_remap_end_vaddr[nid]);
}

void *alloc_remap(int nid, unsigned long size)
{
    void *allocation = node_remap_alloc_vaddr[nid];

    size = ALIGN(size, L1_CACHE_BYTES);

    if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid])
        return NULL;

    node_remap_alloc_vaddr[nid] += size;
    memset(allocation, 0, size);

    return allocation;
}



Comment 2:
A pointer to this space is held not only in the pglist_data instance but also in the global variable mem_map.






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