Chinaunix首页 | 论坛 | 博客
  • 博客访问: 379581
  • 博文数量: 87
  • 博客积分: 983
  • 博客等级: 准尉
  • 技术积分: 685
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-25 07:20
文章分类

全部博文(87)

文章存档

2016年(1)

2015年(3)

2014年(55)

2013年(13)

2012年(15)

分类: LINUX

2014-07-11 16:03:00

bootmem内存的释放

 

free_bootmem

释放一块内存给bootmem分配器。

参数:

1)        addr:待释放内存的物理地址

2)        size待释放内存的大小

 

void __init free_bootmem(unsigned long addr, unsigned long size)

{

#ifdef CONFIG_NO_BOOTMEM

       kmemleak_free_part(__va(addr), size);

       memblock_x86_free_range(addr, addr + size);

#else

       unsigned long start, end;

       /* 内存泄露检测相关,不去管它 */

       kmemleak_free_part(__va(addr), size);

       /* 获得起始pfn */

       start = PFN_UP(addr);

       /* 获得截止pfn */

       end = PFN_DOWN(addr + size);

       /* 将这部分空间对应的位图比特位清0 */

       mark_bootmem(start, end, 0, 0);

#endif

}

 

mark_bootmem

设置某块内存区对应的位图比特位。

参数:

1)        start:起始pfn

2)        end:截止pfnstartend间的bootmem可能分布在不同内存节点的bootmem上。

3)        reserve:比特位0还是1

4)        flags:标志,参见BOOTMEM_EXCLUSIVE

 

static int __init mark_bootmem(unsigned long start, unsigned long end,

                            int reserve, int flags)

{

       unsigned long pos;

       bootmem_data_t *bdata;

       /* pos记录当前标记的位置 */

       pos = start;

       /* 遍历所有节点的bootmem,待标记的内存区可能跨越多个节点 */

       list_for_each_entry(bdata, &bdata_list, list) {

              int err;

              unsigned long max;

/* 如果bootmem跨越了多个节点,那么不同节点的bootmem管理的内存区在地址空间上必须是连续的。bdata_list链表是按地址高低有序的,所以只有在初始时(pos==startpos可能不在bootmem范围内,一旦开始标记,pos必定落在某个节点的bootmem范围内 */

              if (pos < bdata->node_min_pfn ||

                  pos >= bdata->node_low_pfn) {

                     BUG_ON(pos != start);

                     continue;

              }

              /* 获得此次标记的截止pfn */

              max = min(bdata->node_low_pfn, end);

              /* 标记此内存节点bootmem范围内的内存区 */

              err = mark_bootmem_node(bdata, pos, max, reserve, flags);

/* 如果此次标记是分配内存,并且中途放生了错误,释放之前已经分配的内存 */

              if (reserve && err) {

                     mark_bootmem(start, pos, 0, 0);

                     return err;

              }

              /* 如果待标记内存区截止于此节点bootmem范围内,无需扫描下一个节点 */

              if (max == end)

                     return 0;

              /* pos指向本节点bootmem的截止pfn,即下一个节点的起始pfn */

              pos = bdata->node_low_pfn;

       }

       BUG();

}

 

 mark_bootmem_node

标记某个内存节点的bootmem,可能是分配也可能是释放。

static int __init mark_bootmem_node(bootmem_data_t *bdata,

                            unsigned long start, unsigned long end,

                            int reserve, int flags)

{

       unsigned long sidx, eidx;

 

       bdebug("nid=%td start=%lx end=%lx reserve=%d flags=%x\n",

              bdata - bootmem_node_data, start, end, reserve, flags);

       /* 待标记的区间必须位于此节点bootmem */

       BUG_ON(start < bdata->node_min_pfn);

       BUG_ON(end > bdata->node_low_pfn);

       /* 计算起止pfn偏移 */

       sidx = start - bdata->node_min_pfn;

       eidx = end - bdata->node_min_pfn;

      

       if (reserve)

              /* 保留这块bootmem空间*/

              return __reserve(bdata, sidx, eidx, flags);

       else

              /* 释放这块bootmem空间 */

              __free(bdata, sidx, eidx);

       return 0;

}

 

__free

释放一块bootmem空间,即将位图比特位清0

static void __init __free(bootmem_data_t *bdata,

                     unsigned long sidx, unsigned long eidx)

{

       unsigned long idx;

 

       bdebug("nid=%td start=%lx end=%lx\n", bdata - bootmem_node_data,

              sidx + bdata->node_min_pfn,

              eidx + bdata->node_min_pfn);

/* 如果分配bootmem时的优先扫描位置高于释放空间的起始位置,更新优先扫描位置为释放空间的起始位置,这样做有助于减少碎片,使高地址尽可能存在更多的连续的大块空闲空间 */

       if (bdata->hint_idx > sidx)

              bdata->hint_idx = sidx;

       /* sidxeidx之间的比特位清0 */

       for (idx = sidx; idx < eidx; idx++)

              if (!test_and_clear_bit(idx, bdata->node_bootmem_map))

                     BUG();

}

 

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