static inline bool is_buddy_free(struct page *page, struct page *buddy, unsigned int order) { if ((GET_PAGE_FLAG(buddy) & PAGE_BUDDY) && (order == GET_PAGE_ORDER(buddy))) return true; return false; }
void free_pages(struct buddy *node, struct page *page) { struct page *buddy, *mem_map; struct buddy_freelist *freelist; unsigned int order, idx, n; unsigned int irqflag; mem_map = node->mem_map; idx = page - mem_map; order = GET_PAGE_ORDER(page); freelist = &node->freelist[order]; n = 1U << order; spin_lock_irqsave(&node->lock, irqflag); node->nr_free += n; while (order < (BUDDY_MAX_ORDER - 1)) { n = 1U << order; buddy = &mem_map[idx ^ n]; if (!is_buddy_free(page, buddy, order)) break; links_del(&buddy->list); freelist->nr_pageblocks--; RESET_PAGE_FLAG(buddy, PAGE_BUDDY); idx &= ~n; /* grab the head of merging buddies */ order++; freelist++; } page = &mem_map[idx]; links_add(&page->list, &freelist->list); freelist->nr_pageblocks++; SET_PAGE_FLAG(page, PAGE_BUDDY); SET_PAGE_ORDER(page, order); spin_unlock_irqrestore(&node->lock, irqflag); }
void free_pages(struct buddy *pool, struct page *page) { struct page *buddy; struct buddy_freelist *freelist; unsigned int order, index; order = GET_PAGE_ORDER(page); freelist = &pool->free[order]; index = PAGE_INDEX(page->addr); pool->nr_free += 1U << order; while (order < BUDDY_MAX_ORDER) { BITMAP_TOGGLE(freelist->bitmap, index, order); /* If it was 0 before toggling, it means both of buddies * were allocated. So nothing can be merged to upper order * as one of them is still allocated. Otherwise, both of * them are free now. Therefore merge it to upper order. */ if (BITMAP_MASK(freelist->bitmap, index, order)) break; /* find buddy and detach it from current order to merge */ buddy = &mem_map[index ^ (1U << order)]; list_del(&buddy->link); /* grab the first address of merging buddies */ index &= ~(1U << order); order++; freelist++; } list_add(&mem_map[index].link, &freelist->list); RESET_PAGE_FLAG(page, PAGE_BUDDY); }