Pages are divided up into different sized blocks each of which is a power of
two number of pages large. An array of free_area_t structs is
maintained for each order that points to a linked list of blocks of pages that
are free as indicated by Figure 6.1. Hence,
the 0th element of the array will point to a list of free page blocks of
size or 1 page, the 1st element will be a list of
(2) pages up
to
number of pages, the MAX_ORDER been currently
defined as 10. This eliminates the chance that a larger block will be split
to satisfy a request where a smaller block would have sufficed. The page
blocks are maintained on a linear linked list via page
list.
Each zone has a free_area_t struct array called
free_areaMAX_ORDER
. It is declared in
include/linux/mm.h as follows
22 typedef struct free_area_struct { 23 struct list_head free_list; 24 unsigned long *map; 25 } free_area_t;
free_list | A linked list of free page blocks |
map | A bitmap representing the state of a pair of buddies |
Linux saves space by only using one bit to represent each pair of buddies. Each time a buddy is alloc-ed or freed, the bit representing the pair of buddies is toggled so that the bit is zero if the pair of pages are both free or both full and 1 if only one buddy is in use. To toggle the correct bit, the macro MARK_USED in page_alloc.c is used. It is declared as follows
164 #define MARK_USED(index, order, area) \ 165 __change_bit((index) >> (1+(order)), (area)->map)
index is the index of the page within the global mem_map array. By shifting it right by 1+order bits, the bit within map representing the pair of buddies is revealed.