Chapter3:MemoryManagement
The kernel always uses the migrate-type-specificfree_arealist and does not change the migrate type of
any page during the process.
Theset_page_orderhelper function invoked in each step is responsible for setting theprivateflag of
the first instance ofstruct pagein each block to the order currently being processed and for assigning
thePG_buddybit to the page. This indicates that theblock is managed by the buddy system.
If no contiguous memory area is available on the migrate-type-specific list,__rmqueue_smallestreturns
aNULLpointer. The kernel then tries to fulfill the request using other migrate lists based on the fallback
order. The task is delegated to__rmqueue_fallback. Recall from Section 3.5.2 that the fallback order
for migrate types is defined in thefallbacksarray. First of all, the function iterates once again over the
various allocation order lists:
mm/page_alloc.c
static struct page *__rmqueue_fallback(struct zone *zone, int order,
int start_migratetype)
{
struct free_area * area;
int current_order;
struct page *page;
int migratetype, i;
/* Find the largest possible block of pages in the other list */
for (current_order = MAX_ORDER-1; current_order >= order;
--current_order) {
for (i = 0; i < MIGRATE_TYPES - 1; i++) {
migratetype = fallbacks[start_migratetype][i];
...
However, not just the desired migrate type, but also different migrate types as specified in the fallback list
are considered. Notice that the function iterates fromlargetosmallallocation orders! This is done contrary
to the usual strategy, because the kernel wants to take a maximally big block out of foreign allocation
lists if this cannot be avoided. If smaller blocks were favored, this would introduce fragmentation into
the other zone because blocks of different migrate types would be mixed, and this is clearly undesired.
The special zoneMIGRATE_RESERVEcontains emergency reservations and requires special treatment,
discussed below. If the free list for the currently considered migrate type contains free page blocks, the
request can be satisfied from there:
mm/page_alloc.c
/* MIGRATE_RESERVE handled later if necessary */
if (migratetype == MIGRATE_RESERVE)
continue;
area = &(zone->free_area[current_order]);
if (list_empty(&area->free_list[migratetype]))
continue;
page = list_entry(area->free_list[migratetype].next,
struct page, lru);
area->nr_free--;
...