Chapter3:MemoryManagement
type are added to the cache, and one page is removed from the per-CPU list and processed further
below.
If more than one page is to be allocated (as handled in theelsebranch), the kernel callsrmqueueto
select a suitable page block from the zone’s buddy lists. If necessary, the function automatically breaks
down larger blocks and puts unused parts back in the lists (how this is done is described below). Caution:
It can be the case that there are enough free pages in the zone to satisfy the allocation request, but that
the pages arenot contiguous.Inthiscase,rmqueuefails, and aNULLpointer is returned.
Since all failures are handled by jumping to the labelfailed, it is guaranteed thatpagepoints to a
valid sequence of pages once the kernel gets to the current point. Before the pointer can be returned,
prep_new_pagehas to prepare the pages for life in the kernel (note that the function returns a positive
value if something is wrong with the selected pages; in this case, the allocation is restarted from the
beginning):
mm/page_alloc.c
if (prep_new_page(page, order, gfp_flags))
goto again;
return page;
failed:
...
return NULL;
}
prep_new_pageperforms several checks on the pages to ensure that they leave the allocator in a perfect
state — this means, in particular, that the page must not be in use in existing mappings and no incorrect
flags likePG_lockedorPG_buddymay be set because this would imply that the page is in use somewhere
else and should not be on the free list. Normally, however, no error should occur because this would
imply a kernel error elsewhere. The function also sets the following default flags used for each new page:
mm/page_alloc.c
static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
{
page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_readahead |
1 << PG_referenced | 1 << PG_arch_1 |
1 << PG_owner_priv_1 | 1 << PG_mappedtodisk);
...
The meanings of the individual bits are given in Section 3.2.2.prep_new_pageis also invoked to set the
reference counters of the firstpageinstance involved to the initial value of 1. Besides, some more work is
required depending on the page flags:
mm/page_alloc.c
if (gfp_flags & __GFP_ZERO)
prep_zero_page(page, order, gfp_flags);
if (order && (gfp_flags & __GFP_COMP))
prep_compound_page(page, order);
return 0;
}