static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(!PageReserved(p)); // assert(!PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n;//设置空闲块大小为n SetPageProperty(base);//property为置为1表明为空闲的 list_entry_t *le = list_next(&free_list); while (le != &free_list) { p = le2page(le, page_link); le = list_next(le); if (base + base->property == p) { base->property += p->property; SetPageProperty(p); list_del(&(p->page_link)); } else if (p + p->property == base) { p->property += base->property; SetPageProperty(base); base = p; list_del(&(p->page_link)); } } nr_free += n; list_add_before(&free_list, &(base->page_link)); }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(!PageReserved(p) && !PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); list_entry_t *le = list_next(&free_list); // Given Code // while (le != &free_list) { // p = le2page(le, page_link); // le = list_next(le); // if (base + base->property == p) { // base->property += p->property; // ClearPageProperty(p); // list_del(&(p->page_link)); // } // else if (p + p->property == base) { // p->property += base->property; // ClearPageProperty(base); // base = p; // list_del(&(p->page_link)); // } // } // nr_free += n; // list_add(&free_list, &(base->page_link)); while (le != &free_list) { p = le2page(le, page_link); if (base + base->property < p) //已经遍历到第一个地址大于base且无法合并的块,跳出循环 break; le = list_next(le); if (p + p->property == base) { //检查是否是base之前的能合并的块 p->property += base->property; base->flags = base->property = 0; ClearPageProperty(base); base = p; list_del(&(p->page_link)); } else if (base + base->property == p) { //检查是否是base之后能合并的块 base->property += p->property; p->flags = p->property = 0; ClearPageProperty(p); list_del(&(p->page_link)); } } nr_free += n; //空闲空间增加 SetPageProperty(base); //property = 1 list_add_before(le, &(base->page_link)); //插入在第一个第一个地址大于base且无法合并的块之前 }
static struct Page* default_alloc_pages(size_t n) { assert(0 < n); if (nr_free < n) { return 0; } struct Page* page = 0; list_entry_t* le = &free_list; while ((le = list_next(le)) != &free_list) { struct Page* p = le2page(le, page_link); if (n <= p->property) { page = p; break; } } if (page) { list_entry_t* prevLe = list_prev(&(page->page_link)); list_del_init(&(page->page_link)); if (n < page->property) { struct Page* p = page + n; p->property = page->property - n; SetPageProperty(p); list_add(prevLe, &(p->page_link)); } nr_free -= n; ClearPageProperty(page); } return page; }
//buddy_init_memmap - build free_list for Page base follow n continuous pages. static void buddy_init_memmap(struct Page *base, size_t n) { static int zone_num = 0; assert(n > 0 && zone_num < MAX_ZONE_NUM); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p)); p->flags = p->property = 0; p->zone_num = zone_num; set_page_ref(p, 0); } p = zones[zone_num ++].mem_base = base; size_t order = MAX_ORDER, order_size = (1 << order); while (n != 0) { while (n >= order_size) { p->property = order; SetPageProperty(p); list_add(&free_list(order), &(p->page_link)); n -= order_size, p += order_size; nr_free(order) ++; } order --; order_size >>= 1; } }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(!PageReserved(p) && !PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); list_entry_t *le = list_next(&free_list); list_entry_t *insert_loc = &free_list; while (le != &free_list) { p = le2page(le, page_link); le = list_next(le); if (base + base->property == p) { base->property += p->property; ClearPageProperty(p); list_del(&(p->page_link)); } else if (p + p->property == base) { p->property += base->property; ClearPageProperty(base); base = p; list_del(&(p->page_link)); } else if ((unsigned int)p < (unsigned int)base) { insert_loc = &(p->page_link); } } nr_free += n; list_add_after(insert_loc, &(base->page_link)); }
static struct Page * default_alloc_pages(size_t n) { assert(n > 0); if (n > nr_free) { return NULL; } struct Page *found = NULL; list_entry_t *e; for(e = list_next(&free_list); e != &free_list; e = list_next(e)) { struct Page *p = le2page(e, page_link); if(p->property >= n) { found = p; break; } } if(found != NULL) { if(found->property > n) { struct Page *more = found + n; more->property = found->property - n; SetPageProperty(more); list_add_after(&found->page_link, &more->page_link); } list_del(&found->page_link); found->property = 0; ClearPageProperty(found); nr_free -= n; } return found; }
static void default_init_memmap(struct Page *base, size_t n) { // Given Code // assert(n > 0); // struct Page *p = base; // for (; p != base + n; p ++) { // assert(PageReserved(p)); // p->flags = p->property = 0; // set_page_ref(p, 0); // } // base->property = n; // SetPageProperty(base); // nr_free += n; // list_add(&free_list, &(base->page_link)); assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p)); p->flags = p->property = 0; ClearPageProperty(p); set_page_ref(p, 0); } base->property = n; SetPageProperty(base); nr_free += n; list_add(&free_list, &(base->page_link)); }
static struct Page * default_alloc_pages(size_t n) { assert(n > 0); if (n > nr_free) { return NULL; } struct Page *page = NULL; list_entry_t *le = &free_list; while ((le = list_next(le)) != &free_list) { struct Page *p = le2page(le, page_link); if (p->property >= n) { page = p; break; } } if (page != NULL) { list_del(&(page->page_link)); if (page->property > n) { struct Page *p = page + n; p->property = page->property - n; SetPageProperty(p); list_add(&free_list, &(p->page_link)); } nr_free -= n; ClearPageProperty(page); } return page; }
/*buddy_alloc_pages - alloc n page from free area and return the first page. * The header page should set page property flag, and the * property field should assign to n which means next * follow n pages has been allocated. */ struct Page* buddy_alloc_pages(size_t n){ assert(n > 0); if(n > nr_free){ return NULL; } struct Page* page = NULL; uint8_t o = get_ord(n * MIN_BLOCK); uint32_t i = 0; while(1){ if( lft(mem[i]) >= o ) i = lc(i); else if( rht(mem[i]) >= o ) i = rc(i); else break; } if( o == ord(mem[i]) ){ set_rht(mem[i], 0); set_lft(mem[i], 0); page = buddy2page(mem[i], i); assert(!PageReserved(page)); SetPageProperty(page); nr_free -= page->property = 1 << (ord(mem[i]) - 2); update(i); } return page; }
//buddy_alloc_pages_sub - the actual allocation implimentation, return a page whose size >=n, // - the remaining free parts insert to other free list static inline struct Page *buddy_alloc_pages_sub(uint32_t numa_id, size_t order) { assert(order <= MAX_ORDER); size_t cur_order; for (cur_order = order; cur_order <= MAX_ORDER; cur_order++) { if (!list_empty(&free_list(numa_id, cur_order))) { list_entry_t *le = list_next(&free_list(numa_id, cur_order)); struct Page *page = le2page(le, page_link); nr_free(numa_id, cur_order)--; list_del(le); size_t size = 1 << cur_order; while (cur_order > order) { cur_order--; size >>= 1; struct Page *buddy = page + size; buddy->property = cur_order; SetPageProperty(buddy); nr_free(numa_id, cur_order)++; list_add(&free_list(numa_id, cur_order), &(buddy->page_link)); } ClearPageProperty(page); return page; } }
//buddy_init_memmap - build free_list for Page base follow n continuing pages. static void buddy_init_memmap(struct numa_mem_zone *zone) { static int zone_num = 0; size_t n = zone->n; assert(n > 0 && zone_num < MAX_NUMA_MEM_ZONES); zone_num ++; struct Page *base = zone->page; struct Page *p = base; for (; p != base + n; p++) { assert(PageReserved(p)); p->flags = p->property = 0; p->zone_num = zone->id; set_page_ref(p, 0); } //p = zones[zone_num++].mem_base = base; p = base; size_t order = MAX_ORDER, order_size = (1 << order); uint32_t numa_id = zone->node->id; assert(numa_id < sysconf.lnuma_count); while (n != 0) { while (n >= order_size) { p->property = order; SetPageProperty(p); list_add(&free_list(numa_id, order), &(p->page_link)); n -= order_size, p += order_size; nr_free(numa_id, order)++; } order--; order_size >>= 1; } }
// implement the buddy system strategy for freeing page frames void free_pages_bulk(struct Page * page, int order) { int size = 1 << order; unsigned long page_idx = page - mem_map, buddy_idx; struct Page * buddy, * coalesced; while (order < 10) { // calculate the buddy index, by xor operation // if 1 << order bit was previously zero, buddy // index is equal to page_idx + size, conversely, // if the bit was previously one, buddy index is // equal to page_idx - size buddy_idx = page_idx ^ size; buddy = &mem_map[buddy_idx]; if (!page_is_buddy(buddy, order)) break; LIST_REMOVE(buddy, lru); free_area[order].nr_free --; buddy->property = 0; ClearPageProperty(buddy); page_idx &= buddy_idx; order ++; } coalesced = &mem_map[page_idx]; dbmsg("free order %x, page %x\n", order, coalesced - pages); coalesced->property = order; SetPageProperty(coalesced); LIST_INSERT_HEAD(&(free_area[order].free_list), coalesced, lru); free_area[order].nr_free ++; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p) && !PageProperty(p)); p->flags = p->property = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); list_entry_t *le = list_next(&free_list); while (le != &free_list) { p = le2page(le, page_link); if(p > base) break; le = list_next(le); } list_add_before(le, &(base->page_link)); p = le2page(le, page_link); if(le != &free_list && base + base->property == p) { base->property += p->property; ClearPageProperty(p); list_del(&(p->page_link)); } le = list_prev(&(base->page_link)); p = le2page(le, page_link); if (le != &free_list && p + p->property == base) { p->property += base->property; ClearPageProperty(base); list_del(&(base->page_link)); } nr_free += n; /** while (le != &free_list) { p = le2page(le, page_link); le = list_next(le); if (base + base->property == p) { base->property += p->property; ClearPageProperty(p); list_del(&(p->page_link)); } else if (p + p->property == base) { p->property += base->property; ClearPageProperty(base); base = p; list_del(&(p->page_link)); } } nr_free += n; list_add(&free_list, &(base->page_link)); */ }
static void default_init_memmap(struct Page *base, size_t n) { assert(n > 0); // n是页数 struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p)); p->flags = p->property = 0; SetPageProperty(p); set_page_ref(p, 0); // 引用计数设置为0 // 也就是在free_list的前面插入,不过考虑到这是一个双向链表,所以实际的意思是,插到链表的尾部 list_add_before(&free_list, &(p->page_link)); } // 因为base是头表 // property这个玩意只有在free block首地址对应的Page有用,其余都被设置为了0 // 用于指示这个free block一共有多少个free page base->property = n; // 可用的页面数是n SetPageProperty(base); // base所在的页面为头表 nr_free += n; // 空闲的页面数目增加了n //list_add(&free_list, &(base->page_link)); // 添加到free_list的头部 }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); list_entry_t *le = &free_list; struct Page * p; while (p <= base && (le = list_next(le)) != &free_list) p = le2page(le, page_link); for(p=base;p<base+n;p++) { list_add_before(le, &(p->page_link)); p->flags = 0; set_page_ref(p, 0); } base->flags = 0; set_page_ref(base, 0); ClearPageProperty(base); SetPageProperty(base); base->property = n; while (1) { p = le2page(le, page_link); if (base->page_link.next != &free_list && base+base->property==p) { base->property += p->property; p->property = 0; } else break; } le = list_prev(&(base->page_link)); p = le2page(le, page_link); if(le != &free_list && p == base-1) { while (1) { if (p->property) { p->property += base->property; base->property = 0; break; } if (le != &free_list) { le = list_prev(le); p = le2page(le,page_link); } else break; } } nr_free += n; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p) && !PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); struct Page* tempPG = base; for (; tempPG != base + n; tempPG++) { ClearPageReserved(tempPG); SetPageProperty(tempPG); } list_entry_t *le = list_next(&free_list); while (le != &free_list) { p = le2page(le, page_link); le = list_next(le); if (base + base->property == p) { base->property += p->property; p->property = 0; list_del(&(p->page_link)); } else if (p + p->property == base) { p->property += base->property; base->property = 0; list_del(&(p->page_link)); base = p; } } nr_free += n; list_entry_t* rank = &free_list; while((rank=list_next(rank)) != &free_list) { if(le2page(rank, page_link) > base) break; } list_add_before(rank, &(base->page_link)); }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(!PageReserved(p) && !PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); list_entry_t *le = &free_list; while (1) { //TODO: set reserve bits and could be faster le = list_next(le); p = le2page(le, page_link); if (le == &free_list || p > base) { list_add_before(&(p->page_link), &(base->page_link)); break; } } int flag = 1; //cprintf("Now check merge\n"); while (flag == 1) { flag = 0; p = le2page((base->page_link.next), page_link); //cprintf("base = %08x p = %08x size = %d\n", base, p, base->property); //cprintf(" plus = %08x\n", base + base->property); if (base->page_link.next != &free_list && base+base->property==p) { base->property += p->property; //cprintf("merge on the back: %d\n", p->property); ClearPageProperty(p); list_del(&(p->page_link)); //cprintf("flag = %d %d\n", base->flags, p->flags); flag = 1; } p = le2page((base->page_link.prev), page_link); //cprintf("base = %08x p = %08x size = %d\n", base, p, base->property); if (base->page_link.prev != &free_list && p+p->property==base) { p->property += base->property; //cprintf("merge on the front: %d\n", p->property); ClearPageProperty(base); list_del(&(base->page_link)); //cprintf("flag = %d %d\n", base->flags, p->flags); base = p; flag = 1; } } nr_free += n; //list_add(&free_list, &(base->page_link)); }
static void default_init_memmap(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p++) { assert(PageReserved(p)); p->flags = p->property = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); nr_free += n; list_add(&free_list, &(base->page_link)); }
static void default_init_memmap(struct Page *base, size_t n) { assert(n > 0); struct Page *p, *p_end = base + n; for (p = base; p < p_end; p++) { assert(PageReserved(p)); p->flags = p->property = p->ref = 0; } SetPageProperty(base); base->property = n; list_add(&free_list, &(base->page_link)); nr_free += n; }
//static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); assert(PageReserved(base)); //遍历空闲块链表,找到合适的位置插入回收的地址块 list_entry_t *le = &free_list; struct Page *page = NULL; //寻找第一个空闲块 while ((le = list_next(le)) != &free_list) { page = le2page(le, page_link); if (page > base) { break; } } //插入回收的空闲块:按页插入 for (page=base; page<(base+n); page++) { list_add_before(le, &(page->page_link)); } //重置该块的字段 base->flags = 0; base->property = n; set_page_ref(base, 0); ClearPageProperty(base); SetPageProperty(base); //尝试合并地址相连的空闲地址块 //先查看后一个空闲块 page = le2page(le, page_link); //得到后一个空闲块起始地址 if ((base+n) == page) { base->property += page->property; page->property = 0; } //后查看前一个空闲块 le = list_prev(&(base->page_link)); page = le2page(le, page_link); //此时并不是前一个空闲块,而是前一个page if ((le!= &free_list) && page == (base-1)) { while (le!= &free_list) { if (page->property > 0) { page->property += base->property; base->property =0; break; } le = list_prev(le); page = le2page(le, page_link); } } nr_free += n; return; }
static void default_init_memmap(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p)); p->flags = 0; // Clears the flags. p->property = 0; // Not the first page of free block. set_page_ref(p, 0); // Free and no reference. } SetPageProperty(base); // Valid page. list_add(&free_list, &(base->page_link)); // Links this page to free_list base->property = n; // First page of n free blocks. nr_free += n; }
static void default_init_memmap(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p)); p->flags = 0; // init p->flags as 0 SetPageProperty(p); // p->flags should be set bit PG_property p->property = 0; // p->property should be set to 0 set_page_ref(p, 0); // p->ref should be 0, because now p is free and no reference list_add_before(&free_list, &(p->page_link)); // link this page to free_list } base->property = n; // for the first page of free block, its property should be set to total num of block nr_free += n; // sum the number of free mem block }
static void default_free_pages(struct Page *base, size_t n) { // 用于释放页 // 我们来仔细看一下释放page的函数吧! assert(n > 0); assert(PageReserved(base)); list_entry_t *le = &free_list; // le指向空闲段链表的头部 struct Page *p; while ((le = list_next(le)) != &free_list) { // 开始遍历 p = le2page(le, page_link); if (p > base) { // free_list里面的数据都是按照地址从小到大排列的吧! break; } } // le现在指向一个恰好在base页面之后的page for (p = base; p < base + n; p++) { // 不断地在前面插入 list_add_before(le, &(p->page_link)); } base->flags = 0; set_page_ref(base, 0); // 引用计数变为了0 ClearPageProperty(base); // SetPageProperty(base); // 只需要这句就行了吧! base->property = n; p = le2page(le, page_link); if (base + n == p) { // 也就是说,前后可以连接起来 base->property += p->property; p->property = 0; } le = list_prev(&(base->page_link)); p = le2page(le, page_link); // 找到free_list中base之前的那个free page if (le != &free_list && p == base - 1) { // 如果两个也可以连起来 while (le != &free_list) { if (p->property) { p->property += base->property; base->property = 0; break; } le = list_prev(le); p = le2page(le, page_link); } } nr_free += n; // 空闲页的计数加n return; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); assert(PageReserved(base)); list_entry_t *le = &free_list; struct Page * p; while((le=list_next(le)) != &free_list) { p = le2page(le, page_link); if(p>base){ break; } } // 每个page都加入freelist for(p=base;p<base+n;p++){ list_add_before(le, &(p->page_link)); } // 首个page进行设置 base->flags = 0; set_page_ref(base, 0); ClearPageProperty(base); SetPageProperty(base); base->property = n; p = le2page(le,page_link); // 如果后面需要合并 if( base+n == p ){ base->property += p->property; p->property = 0; } le = list_prev(&(base->page_link)); p = le2page(le, page_link); // 如果前面需要合并 if(le!=&free_list && p==base-1){ while(le!=&free_list){ if(p->property){ p->property += base->property; base->property = 0; break; } le = list_prev(le); p = le2page(le,page_link); } } nr_free += n; return ; }
static void default_init_memmap(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(PageReserved(p)); p->flags = 0; SetPageProperty(p); p->property = 0; set_page_ref(p, 0); list_add_before(&free_list, &(p->page_link)); } nr_free += n; //first block base->property = n; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(!PageReserved(p) && !PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); list_entry_t *le = list_next(&free_list); while (le != &free_list) { p = le2page(le, page_link); le = list_next(le); if (base + base->property == p) { base->property += p->property; ClearPageProperty(p); list_del(&(p->page_link)); } else if (p + p->property == base) { p->property += base->property; ClearPageProperty(base); base = p; list_del(&(p->page_link)); }else{ if(base + base->property < p && p->page_link.prev == &free_list){ list_add(&free_list , &base->page_link); nr_free += n; return ; }else if(le == &free_list && p+p->property < base){ list_add_before(&free_list , &base->page_link); nr_free += n; return ; }else { struct Page *page_next = le2page(le , page_link); if(p+p->property < base && base+base->property<page_next){ list_add(p , &base->page_link); nr_free += n; return ; } } } } nr_free += n; list_add(&free_list, &(base->page_link)); }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); assert(PageReserved(base)); list_entry_t *le = &free_list; //获取空闲内存页的起始地址 struct Page *p; while((le = list_next(le))!= &free_list){ p = le2page(le, page_link); if( p > base){ //说明base应该接到p的前面,也就是le的前面 break; } } for( p = base; p<base+n; p++){ list_add_before(le, &(p->page_link)); } base->flags = 0; set_page_ref(base, 0); ClearPageProperty(base); SetPageProperty(base); base->property = n; //下面是块的合并 //向后 p = le2page(le, page_link); if(base+n == p){ base->property += p->property; p->property = 0; } //向前 le = list_prev(&(base->page_link)); p = le2page(le, page_link); if(le!=&free_list && p == base-1){ while(le!=&free_list){ if(p->property){ p->property += base->property; base->property = 0; break; } le = list_prev(le); p = le2page(le, page_link); } } nr_free += n; return ; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); assert(PageReserved(base)); struct Page *p = base; struct Page * q = NULL; list_entry_t * le = &free_list; while((le = list_next(le)) != &free_list) { q = le2page(le,page_link); if(q > base) break; } //struct Page * q = for(;p < base + n;p++){ list_add_before(le,&(p -> page_link)); } base -> flags = 0; set_page_ref(base,0); ClearPageProperty(base); SetPageProperty(base); base->property = n; if(q == base + n){ base -> property += q -> property; q -> property = 0; } le = list_prev(&(base -> page_link)); q = le2page(le,page_link); if(le != &free_list && q == base -1) { while(le != &free_list){ if(q -> property) { q -> property += base -> property; base -> property = 0; break; } le = list_prev(le); q = le2page(le,page_link); } } nr_free += n; return; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); // (5.1) list_entry_t *le = &free_list; while ((le = list_next(le)) != &free_list) { if (le2page(le, page_link) > base) { // the first position higher than base break; } } struct Page *p; for (p = base; p < base + n; p++) { // insert these pages p->property = 0; list_add_before(le, &(p->page_link)); } // (5.2) mark base as free page base->flags = 0; SetPageProperty(base); base->property = n; set_page_ref(base, 0); // (5.3) p = le2page(le, page_link); if (p == base + n) { // merge forward base->property += p->property; // merge p into base p->property = 0; } le = list_prev(&(base->page_link)); p = le2page(le, page_link); // prev of base if (p == base - 1) { // merge backward for (; le != &free_list; le = list_prev(le)) { p = le2page(le, page_link); if (p->property > 0) { // find property, merge base into p p->property += base->property; base->property = 0; break; } } } nr_free += n; }
static void default_free_pages(struct Page *base, size_t n) { assert(n > 0); struct Page *p = base; for (; p != base + n; p ++) { assert(!PageReserved(p) && !PageProperty(p)); p->flags = 0; set_page_ref(p, 0); } base->property = n; SetPageProperty(base); list_entry_t *le = list_next(&free_list); while(1) { p = le2page(le, page_link); if (le == &free_list || p >= base) { list_add_before(le, &(base->page_link)); break; } le = list_next(le); } // Search Next le = list_next(&(base->page_link)); if(le != &free_list) { p = le2page(le, page_link); if(base + n == p) { // Link them base->property += p->property; ClearPageProperty(p); list_del(&(p->page_link)); } } // Search Prev le = list_prev(&(base->page_link)); if(le != &free_list) { p = le2page(le, page_link); if(p + p->property == base) { // Link them p->property += base->property; ClearPageProperty(base); list_del(&(base->page_link)); } } nr_free += n; }