Пример #1
0
struct page *alloc_pages(struct buddy *node, unsigned int order)
{
	struct page *page;
	struct buddy_freelist *freelist;
	struct links *head, *curr;
	unsigned int i, n;

	freelist = &node->freelist[order];
	page = NULL;

	unsigned int irqflag;
	spin_lock_irqsave(&node->lock, irqflag);

	for (i = order; i < BUDDY_MAX_ORDER; i++, freelist++) {
		head = &freelist->list;
		curr = head->next;

		if (curr == head)
			continue;

		page = get_container_of(curr, struct page, list);
		RESET_PAGE_FLAG(page, PAGE_BUDDY);
		links_del(curr);
		freelist->nr_pageblocks--;

		/* split in half to add one of them to the current order list
		 * if allocating from a higher order */
		while (i > order) {
			freelist--;
			i--;
			n = 1U << i;

			SET_PAGE_FLAG(&page[n], PAGE_BUDDY);
			SET_PAGE_ORDER(&page[n], i);
			links_add(&page[n].list, &freelist->list);
			freelist->nr_pageblocks++;
		}

		node->nr_free -= 1 << order;

		RESET_PAGE_FLAG(page, PAGE_BUDDY);
		SET_PAGE_ORDER(page, i);
		break;
	}

	spin_unlock_irqrestore(&node->lock, irqflag);

	return page;
}
Пример #2
0
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);
}
Пример #3
0
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);
}