Chinaunix首页 | 论坛 | 博客
  • 博客访问: 697970
  • 博文数量: 183
  • 博客积分: 2650
  • 博客等级: 少校
  • 技术积分: 1428
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-22 17:02
文章分类
文章存档

2017年(1)

2015年(46)

2014年(4)

2013年(8)

2012年(2)

2011年(27)

2010年(35)

2009年(60)

分类: LINUX

2009-10-09 22:57:19

再来看一个多页面的释放操作,调用__free_pages_ok(),代码如下:

//释放的起始页面:page

//页面个数:2^order

void __free_pages_ok(struct page *page, unsigned int order)

{

                              //声时并初始化一个链表

                              LIST_HEAD(list);

                              int i;

 

                              arch_free_page(page, order);

 

                              mod_page_state(pgfree, 1 << order);

                              for (i = 0 ; i < (1 << order) ; ++i)

                                 free_pages_check(__FUNCTION__, page + i);

                              list_add(&page->lru, &list);

                              kernel_map_pages(page, 1<

                              free_pages_bulk(page_zone(page), 1, &list, order);

}

它的核心处理都是在free_pages_bulk()完成的

//cout:释放的次数

//order:每次释放2^order个页面

//例如:要释放x个单页面,count = x order=0

//释放2^x大小的连续页面 count = 1 order = x

static int

free_pages_bulk(struct zone *zone, int count,

                                 struct list_head *list, unsigned int order)

{

                              unsigned long flags;

                              struct free_area *area;

                              struct page *base, *page = NULL;

                              int ret = 0;

 

                              base = zone->zone_mem_map;

                              //找到要释放大小页面的空闲链

                              area = zone->free_area + order;

                              spin_lock_irqsave(&zone->lock, flags);

                              zone->all_unreclaimable = 0;

                              zone->pages_scanned = 0;

                              //如果页面释放完了,或者循环次数已尽

                              while (!list_empty(list) && count--) {

                                 page = list_entry(list->prev, struct page, lru);

                                 /* have to delete it as __free_pages_bulk list manipulates */

                                 list_del(&page->lru);

                                 __free_pages_bulk(page, base, zone, area, order);

                                 ret++;

                              }

                              spin_unlock_irqrestore(&zone->lock, flags);

                              return ret;

}

调用__free_pages_bulk(),代码如下:

参数含义:

Page:要释放的超始page

Base:对应zone的页数组的首地址

Zone:

Area:将页面释放到此空闲区

Order:释放的连续空闲区大小

static inline void __free_pages_bulk (struct page *page, struct page *base,

                                 struct zone *zone, struct free_area *area, unsigned int order)

{

                              unsigned long page_idx, index, mask;

 

                              if (order)

                                 destroy_compound_page(page, order);

                              //假设order = 3

                              //mask = 1111 1000

                              mask = (~0UL) << order;

                              //取得页在zone中页数组中的序号

                              page_idx = page - base;

                              //~mask:0000 0111

                              //判断page_idx是不是order位对齐的

                              //结合前面alloc所分析的,不难得出在2^order大小空闲区中.

                              //空闲块的首地址必须是2^order的倍数

                              if (page_idx & ~mask)

                                 BUG();

                              //得到page在链表中的分配位图对应位,前面已经介绍过

                              index = page_idx >> (1 + order);

                             

                              //更新zone 的空闲区统计计数

                              zone->free_pages += 1 << order;

                              //循环,合并内存

                              while (order < MAX_ORDER-1) {

                                 struct page *buddy1, *buddy2;

 

                                 BUG_ON(area >= zone->free_area + MAX_ORDER);

       //判断相邻块是否空闲.前面说过,0的时候,是两者都空闲或//两者都分配出去了

                                 if (!__test_and_change_bit(index, area->map))

                                     /*

                                      * the buddy page is still allocated.

                                      */

                                     break;

 

                                 /* Move the buddy up one level. */

                              //相邻块是空闲的

                                 //它的邻居块

                                 buddy1 = base + (page_idx ^ (1 << order));

                                 //它自已

                                 buddy2 = base + page_idx;

                                 //判断是否超过zone所允许的page范围

                                 BUG_ON(bad_range(zone, buddy1));

                                 BUG_ON(bad_range(zone, buddy2));

                                 //将其从现有的空闲链中脱落

                                 list_del(&buddy1->lru);

                                 //到它的上一级,判断是否有能合并的内存块

                                 mask <<= 1;

                                 order++;

                                 area++;

                                 index >>= 1;

                                 page_idx &= mask;

                              }

                              list_add(&(base + page_idx)->lru, &area->free_list);}

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