Chinaunix首页 | 论坛 | 博客
  • 博客访问: 49881
  • 博文数量: 68
  • 博客积分: 71
  • 博客等级: 民兵
  • 技术积分: 700
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-18 12:13
文章分类

全部博文(68)

文章存档

2015年(68)

我的朋友

分类: LINUX

2015-05-10 17:18:23

1. 
// 按照 node_min_pfn 从小到大的顺序串联 bootmem_data_t
// 发现这个链表实际是将整个内存区域给链在了一起,如果两块64M的内存(两个Node),那么每一块用bootmem_data_t结构体来描述,然后这个链表将这两个描述链在一起
static void __init link_bootmem(bootmem_data_t *bdata)
{
        struct list_head *iter;


        list_for_each(iter, &bdata_list) {
                bootmem_data_t *ent;


                ent = list_entry(iter, bootmem_data_t, list);
                if (bdata->node_min_pfn < ent->node_min_pfn)
                        break;
        }
        list_add_tail(&bdata->list, iter);////将节点挂在本节点前,返回
}




    static unsigned long __init init_bootmem_core(bootmem_data_t *bdata,  
        unsigned long mapstart, unsigned long start, unsigned long end)  
    {  
        unsigned long mapsize;  
      
        mminit_validate_memmodel_limits(&start, &end);  
        bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));/*存储位图起始地址的虚拟地址*/  
        bdata->node_min_pfn = start;/*节点中的起始页*/  
        bdata->node_low_pfn = end;  /*节点中的终止页*/  
        link_bootmem(bdata);/*将该bdata按顺序链入bdata_list中*/  
      
        /* 
         * Initially all pages are reserved - setup_arch() has to 
         * register free RAM areas explicitly. 
         */  
        mapsize = bootmap_bytes(end - start);  //计算所需要的最少字节数。有mapsize这么大的字节数,就可以使用每比特去描述每个page
        //此时,node_bootmem_map开始的每一个bit,就代表一个对应的页的状态是否是保留状态;这些可以由 test_and_set_bit\test_and_clear_bit\test_bit等进行查看或者设置
        memset(bdata->node_bootmem_map, 0xff, mapsize);/*将位图全部置1,保留所有页*/  
      
        bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx\n",  
            bdata - bootmem_node_data, start, mapstart, end, mapsize);  
      
        return mapsize;/*返回位图大小*/  
    }  


static inline int test_and_set_bit(int nr, volatile unsigned long *addr)//从addr开始,往后数nr个bit,选中这个bit,然后将这个bit设置为1,将这个bit的old值返回


static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)//从addr开始,往后数nr个bit,选中这个bit,然后将这个bit设置为0,将这个bit的old值返回


static inline int test_bit(int nr, const volatile unsigned long *addr)//从addr开始,往后数nr个bit,选中这个bit,然后测试这个bit是否为1






alloc_bootmem_core(struct bootmem_data *bdata,  
                    unsigned long size, //申请的大小
                    unsigned long align,  //对齐字节
                    unsigned long goal, //开始地址(全局地址,如无则从bdata开始地址起)
                    unsigned long limit //操作的最大地址
)  
{
..........................
        //此句之前的其实都是在物理内存的数据结构中进行查找的,一旦查找到了,那么就将起始地址转换成线性地址,最后返回的就是线性地址
        region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) + /*得到起始地址的虚拟地址*/  
                start_off);  
        memset(region, 0, size);/*将申请到的区域清空*/  
        /* 
         * The min_count is set to 0 so that bootmem allocated blocks 
         * are never reported as leaks. 
         */  
        kmemleak_alloc(region, size, 0, 0);  
        return region;  
}




//
static unsigned long __init bootmap_bytes(unsigned long pages)
{
        unsigned long bytes = (pages + 7) / 8;   // 这个是page的数量对8向上取整数,表示至少需要bytes个字节,可以每比特描述一个page


        return ALIGN(bytes, sizeof(long));        // ??? free_all_bootmem_core中对vec的取值,需要一次搞一个long型的,所以此处需要对long对齐
}


//使用比特来描述page是保留与否的状态,那么有多少页就需要多少比特,使用能满足的最少页面数对应的内存容量来使用这些bit
unsigned long __init bootmem_bootmap_pages(unsigned long pages)        //为了计算pages数量的内存页,至少需要多少页面对应的内存,才能进行内存的每比特描述一个page
{
        unsigned long bytes = bootmap_bytes(pages);


        return PAGE_ALIGN(bytes) >> PAGE_SHIFT;        // bytes对4K向上取整数,表示至少需要这么多页面对应的内存可以提供 内存的每比特描述一个page
}




/////////////////////////////////////////////////////////////////


static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)  
{  
    int aligned;  
    struct page *page;  
    unsigned long start, end, pages, count = 0;  
  
    if (!bdata->node_bootmem_map)/*bitmap不存在,表示该节点已经释放*/  
        return 0;  
  
    /*获得低端内存的起始页框和终止页框*/  
    start = bdata->node_min_pfn;  
    end = bdata->node_low_pfn;  
  
    /* 
     * If the start is aligned to the machines wordsize, we might 
     * be able to free pages in bulks of that order. 
     */  
    aligned = !(start & (BITS_PER_LONG - 1));// 这个应该是判断 start的值 是否是 本机器的字节宽度的整数倍,32位机器对应的是 32 比特 对齐
  
    bdebug("nid=%td start=%lx end=%lx aligned=%d\n",  
        bdata - bootmem_node_data, start, end, aligned);  
  
    /************************************* 
    *         第一步:释放空闲页          * 
    *************************************/  
    while (start < end) {  
        unsigned long *map, idx, vec;  
  
        map = bdata->node_bootmem_map;  
        idx = start - bdata->node_min_pfn;  
        vec = ~map[idx / BITS_PER_LONG];/*将idx所处的long字段的位图部分进行取反*/  //这个操作还需要仔细研究,参考bootmap_bytes对long对齐这一步
        //根据bootmap_bytes的实现,可以看到node_bootmem_map开始的每个字节,都是对8个page的描述。而且需要的字节数根据处理后,是以long对齐的。
        //idx表示的是某个page,对应到node_bootmem_map开始的某个字节的某个比特上,所以使用 idx / BITS_PER_LONG 可以计算这个idx对应到哪个long型上,然后可以在map中取到这个long值,然后按位取反赋给vec
        //map中的每个bit位都是描述对应的page的;使用此处的操作,是将idx所在的连续的32个元素取出来,每个元素肯定是0或者1,那么就可以使用这32个0/1组成一个long型数值,存入vec中
        //  bit       0   1   2   3   4   5   6   7    8......   31    32   33   34   35   36 ...    63   64   65 ...          
        //  byte      |              0            |    |1 |  |2|。。。。。。。。。。。。。。。。。。。。。          
        //  long      |                       0                   |     |                    1        |   |          2..............




        /*如果:1.起始地址是2的整数幂 
               2.该long字段的位图全为0,即空闲状态
               3.start+BITS_PER_LONG未超过范围*/  
        if (aligned && vec == ~0UL && start + BITS_PER_LONG < end) {  
            int order = ilog2(BITS_PER_LONG);/*得到Long的长度为2的多少次幂*/  
  
            __free_pages_bootmem(pfn_to_page(start), order);/*直接将整块内存释放*/  // order = 5或者6,  32、64个page一次性释放掉
            count += BITS_PER_LONG;                         // count统计总共释放的page数,此时可以添加 32、64个 
        } else {/*否则只能逐页释放*/  
            unsigned long off = 0;  
  
            while (vec && off < BITS_PER_LONG) {/*判断该字段内的空闲页是否已经释放完*/  
                if (vec & 1) { /*vec的最低位为1,也就是说start+off对应的page为空闲*/  //vec是long型,每一个bit都是对一个page的描述,先从最低的bit开始判断,然后vec不停右移,计算更高位的bit
                    page = pfn_to_page(start + off);          //vec & 1 就是取vec的最低一位,判断描述bit是否是0,是的话才能释放的
                    __free_pages_bootmem(page, 0);  
                    count++;  
                }  
                vec >>= 1;  // vec不停右移,更高位的bit被移动到最低位,这样在下次计算 vec & 1时,取到最低位
                off++;  
            }  
        }  
        start += BITS_PER_LONG;  // ???此处有个疑问,如果end与start的差距不是 32的整数倍,那么内层while循环,会导致 多释放页面吗?此时 start+32 超过了end,进入else分支,但是使用off < 32 来判断,所以会多释放 (32-(end-start))个page啊
    }  
  
    /***************************** 
    *  第二步:释放保存bitmap的页 * // 在bootmem_bootmap_pages中可以计算pages个页面需要多少内存,将需要的内存用page(4K)的个数表示
    ******************************/  
    page = virt_to_page(bdata->node_bootmem_map);/*得到bitmap起始地址的所属页*/  
    pages = bdata->node_low_pfn - bdata->node_min_pfn;  
    pages = bootmem_bootmap_pages(pages);/*得到bitmap的大小,以页为单位*/  //这两步的pages是不同的含义,入参的pages是 map图需要表示的页面数量,返回的值是map图占用的内存是多大,需要多少个page(4K)
    count += pages;                          // map图自身占用的内存是多少个page,释放掉,此时count就又增加了这么多个page
    while (pages--)/*逐页释放*/  
        __free_pages_bootmem(page++, 0);  
  
    bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count);  
  
    return count;/*返回释放的页框数*/  





阅读(792) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:【编译】Linux环境编译traceroute

给主人留下些什么吧!~~