Пример #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
static void buddy_freelist_init(struct buddy *node, size_t nr_pages,
		struct page *mem_map)
{
	extern unsigned int _ram_start;
	unsigned int order, idx, preserved, nr_free, n;

	/* Preserve the initial kernel stack to be free later, which is located
	 * at the end of memory */
	preserved = nr_pages - PAGE_NR(ALIGN_PAGE(STACK_SIZE));
	order = mylog2(PAGE_NR(ALIGN_PAGE(STACK_SIZE)));
	SET_PAGE_ORDER(&mem_map[preserved], order);

	/* And mark kernel .data and .bss sections as used.
	 * The region of mem_map array as well. */
	idx = PAGE_NR(ALIGN_PAGE(&mem_map[nr_pages]) -
			(unsigned int)&_ram_start);
	nr_free = preserved - idx;
	debug(MSG_DEBUG, "The first free page(idx:%d) - %x",
			idx, &mem_map[nr_pages]);
	debug(MSG_DEBUG, "The number of free pages %d", nr_free);

	struct page *page;

	while (nr_free) {
		order = min(mylog2(idx), BUDDY_MAX_ORDER - 1);
		while ((int)(nr_free - (1U << order)) < 0)
			order--;

		page = &mem_map[idx];
		SET_PAGE_ORDER(page, order);
		SET_PAGE_FLAG(page, PAGE_BUDDY);
		links_add(&page->list, &node->freelist[order].list);

		node->freelist[order].nr_pageblocks++;
		debug(MSG_DEBUG, "%02d %x added to %x", order, &page->list,
				&node->freelist[order].list);

		n = 1U << order;
		debug(MSG_DEBUG, "%04d: idx %d buddy %d head %d",
				n, idx, idx ^ n, idx & ~n);
		idx += n;
		nr_free -= n;
		node->nr_free += n; /* total pages being managed by buddy */
		debug(MSG_DEBUG, "order %d, nr_free %d, next %d\n",
				order, nr_free, idx);
	}
}
Пример #3
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);
}
Пример #4
0
struct page *alloc_pages(struct buddy *pool, unsigned int order)
{
	struct buddy_freelist *freelist = &pool->free[order];
	struct list *head, *curr;
	struct page *page;
	unsigned int i;

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

		if (curr != head) {
			page = get_container_of(curr, struct page, link);

			list_del(curr);
			BITMAP_TOGGLE(freelist->bitmap,
					PAGE_INDEX(page->addr), i);

			/* if allocating from higher order, split in half to add
			 * one of them to current order. */
			while (i > order) {
				freelist--;
				i--;

				list_add(&page->link, &freelist->list);
				BITMAP_TOGGLE(freelist->bitmap,
						PAGE_INDEX(page->addr), i);

				page += 1 << i;
			}

			pool->nr_free -= 1 << order;

			SET_PAGE_ORDER(page, order);
			SET_PAGE_FLAG(page, PAGE_BUDDY);

			return page;
		}
	}