mem_init()

原本由bootmem管理的内存在mem_init函数中交由伙伴系统管理。

1.free_unused_memmap_node

相邻的membank间可能存在空洞,但在bootmem阶段这些空洞页也分配了page结构体。该函数的作用是找到这些page结构体所占用的内存并且释放掉。

static void __init free_unused_memmap_node(int node, struct meminfo *mi)
    -->unsigned long bank_start; //前一个membank的结束地址
    -->unsigned long prev_bank_end ;//后一个membank的起始地址
    -->free_memmap(node, prev_bank_end, bank_start);
        -->struct page *start_pg = pfn_to_page(prev_bank_end);
        -->struct page *end_pg = pfn_to_page(bank_start);
        -->unsigned long pg = PAGE_ALIGN(__pa(start_pg));
        -->unsigned long pgend = __pa(end_pg) & PAGE_MASK;
        -->free_bootmem_node(NODE_DATA(node), pg, pgend - pg);

2.移交bootmem分配剩余的空闲页到伙伴系统

该函数返回的是返回给伙伴系统的空闲页数。

unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
{
    register_page_bootmem_info_node(pgdat);
    return free_all_bootmem_core(pgdat->bdata);
}

空闲页保存在全局变量totalram_pages中

 

/*mm/page_alloc.c*/
unsigned long totalram_pages __read_mostly;

totalram_pages += free_all_bootmem_node(pgdat);

2.1该函数的核心是free_all_bootmem_core(pgdat->bdata)

static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
    -->__free_pages_bootmem(pfn_to_page(start), order);
    -->释放掉bdata->node_bootmem_map所占用的内存,彻底废弃bootmem分配器

释放页到伙伴系统底层调用的两个函数是

void __free_pages(struct page *page, unsigned int order)
#define __free_page(page) __free_pages((page), 0)

可以看到,最终调用的还是__free_pages函数

void __free_pages(struct page *page, unsigned int order)
{
    if (put_page_testzero(page)) {
        if (order == 0)
            free_hot_page(page);
        else
            __free_pages_ok(page, order);
    }
}

free_hot_page流程如下

free_hot_page(page);
    -->free_hot_cold_page(page, 0);
        -->struct zone *zone = page_zone(page);
        -->struct per_cpu_pages *pcp = &zone_pcp(zone, get_cpu())->pcp;
        -->if (cold)
            list_add_tail(&page->lru, &pcp->list);/*冷页插入队列末尾*/
           else
            list_add(&page->lru, &pcp->list);/*热页插入队列首*/
        -->pcp->count++;
        -->if (pcp->count >= pcp->high)
            -->free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
                -->从队列末尾开始删除pcp->batch个页
                -->__free_one_page(page, zone, order);/*把删除的页释放到伙伴系统*/

__free_pages_ok流程如下:

static void __free_pages_ok(struct page *page, unsigned int order)
    -->free_one_page(page_zone(page), page, order);
        -->__free_one_page(page, zone, order);

可以看出,最终调用相同的底层函数__free_one_page,这个函数的实现可以说是伙伴系统的精髓。

这里注意空闲页加入伙伴系统后要做如下的设置。

set_page_order(page, order);
    -->set_page_private(page, order);/*设置page->private*/
    -->__SetPageBuddy(page);/*设置page->flags*/
list_add(&page->lru,&zone->free_area[order].free_list[migratetype]);
zone->free_area[order].nr_free++;

 

posted @ 2018-08-24 21:39  bluebluebluesky  阅读(1165)  评论(0编辑  收藏  举报