Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3883780
  • 博文数量: 146
  • 博客积分: 3918
  • 博客等级: 少校
  • 技术积分: 8585
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-17 13:52
个人简介

个人微薄: weibo.com/manuscola

文章分类

全部博文(146)

文章存档

2016年(3)

2015年(2)

2014年(5)

2013年(42)

2012年(31)

2011年(58)

2010年(5)

分类:

2011-05-11 20:41:02

释放比较简单,先描述释放
free_bootmem  和free_bootmem_node是提供的两个API接口

free_bootmem_node 提供了内存节点,另一需要遍历所有节点
void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
                              unsigned long size)
{
        free_bootmem_core(pgdat->bdata, physaddr, size);
}


void __init free_bootmem(unsigned long addr, unsigned long size)
{
        bootmem_data_t *bdata;
        list_for_each_entry(bdata, &bdata_list, list)
                free_bootmem_core(bdata, addr, size);
}

free_bootmem_core 是真正干活的函数
释放内存,需要两个参数,释放内存的起始地址 addr 和要释放的内存的大小size。
实际情况也是如此。
static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
                                     unsigned long size)

bootmem分配器是最先适配的算法,用位图来描述某个页面是否使用。这个函数的核心部分是
for (i = sidx; i < eidx; i++) {
                if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map)))
                        BUG();
}

简单的说,就是计算出sidx的含义是 以node_boot_start 为起始页面(第0页),addr所在的页面是
第几个页面。 eidx同样道理,(addr+size)所在页面相对于起始页面,是第几页。
将sidx和eidx之间的页面对应的位置,在位图中清零。

----------------------------------------------------------------------------------------------
其次是分配内存。稍微复杂一些。
下面的API接口
alloc_bootmem 
alloc_bootmem_pages
alloc_bootmem_low
alloc_bootmem_low_pages
这些API函数只需要一个参数,size 即大小。需要分配多大的空间。

这个_pages 后缀的意思是指数据的对齐方式是按页对齐。
_low后缀的意思是数据从ZONE_DMA内存域开始分配内存。需要DMA内存时才使用带low的分配函数。

这些函数是__alloc_bootmem前端函数


alloc_bootmem 
                 =======> __alloc_bootmem  ====>  __alloc_bootmem_nopanic====> __alloc_bootmem_core
alloc_bootmem_pages   

alloc_bootmem_low
                         =====>__alloc_bootmem_low    =================>  __alloc_bootmem_core
alloc_bootmem_low_pages

__alloc_bootmem_core 比较命苦,实际干活的函数都是它。这个函数比较长。

void * __init
__alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
              unsigned long align, unsigned long goal, unsigned long limit)

一共五个参数
第一个参数比较简单,是老朋友了。
第二个参数比较简单,是API 接口的唯一一个参数,由接口调用者指定
第三个参数是align,对齐方式。 对齐方式有两种 PAGE_SIZE 和SMP_CACHE_BYTES.
SMP_CACHE_BYTES 在大多数的体系结构中使数据理想的置于L1高速缓存
PAGE_SIZE  按照页对齐。API带后缀pages的都是按照PAGE_SiZE对齐。如alloc_bootmem_pages。
第四个参数 goal ,目的地。一般是ZONE_NORMAL内存,API后缀带low的表示分配到ZONE_DMA.
第五个参数 分配的上限,不能超过这个地址。


areasize = (size + PAGE_SIZE-1) / PAGE_SIZE;
areasize表示实际要分配几个页面。
preferred 表示从哪个起始位置开始查找 areasize个可用的页面。
preferred = bdata->last_success - node_boot_start;
preferred = PFN_DOWN(ALIGN(preferred, align));
这个preferred的存在是为了加快查找。bootmem_data数据结构中有个
成员变量为last_success。

eidx = end_pfn - PFN_DOWN(node_boot_start);
end_pfn 如limit为0,则为bdata->node_low_pfn,
否则,选择 limit 和bdata->node_low_pfn 小的哪个。、

然后就到了很复杂的循环体了。
循环体的工作就是找areasize 个连续页面即位图对应位置为0,页面可用,
从preferred 开始找。如果找到最后了,即大于eidx了,还是没找到。并且
preferred大于0,那么从零再次开始找。

如果找到了,记录下其实位置。
start = i;
bdata->last_success = PFN_PHYS(start) + node_boot_start;//记录下成功的物理地址,用于下次查找。


if (align < PAGE_SIZE &&
            bdata->last_offset && bdata->last_pos+1 == start) 
如果不是按页分配,就是说分配的单位比较小,并且,上次分配的没有分配完整页面,而本次选的start页面
是上次选择的下一页面,可以考虑将上次分配页面的剩余空间利用起来。

offset = ALIGN(bdata->last_offset, align);
remaining_size = PAGE_SIZE - offset ;//上次分配页面的剩余可用空间。
if (size < remaining_size) 如果本次分配的size比较小,小于remaining_size,
OK,不要浪费,就用上次剩下的边角料。
               bdata->last_offset = offset + size;
               ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
                                           offset + node_boot_start);

else {
                        remaining_size = size - remaining_size;
                        areasize = (remaining_size + PAGE_SIZE-1) / PAGE_SIZE;
                        ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
                                           offset + node_boot_start);
                        bdata->last_pos = start + areasize - 1;
                        bdata->last_offset = remaining_size;
      }

size大于remaining_size,还是要充分利用边角料。注意维护ret  bdata->last_pos bdata->last_offset。
阅读(2191) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~