在buddy算法中,每一页都有一个buddy页与之相对应,使用__page_find_buddy函数可以找到指定页面对应的buddy页面:/** Locate the struct page for both the matching buddy in our* pair (buddy1) and the combined O(n+1) page they form (page).** 1) Any buddy B1 will have an order O twin B2 which satisfies* the following equation:*B2 = B1 ^ (1 << O)* For example, if the starting buddy (buddy2) is #8 its order* 1 buddy is #10:*B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10** 2) Any buddy B will have an order O+1 parent P which* satisfies the following equation:*P = B & ~(1 << O)** Assumption: *_mem_map is contiguous at least up to MAX_ORDER*/staticinlinestruct page *__page_find_buddy(struct page *page, unsignedlong page_idx, unsignedint order){unsignedlong buddy_idx = page_idx ^ (1 << order);return page + (buddy_idx - page_idx);}由于每一页都可能属于不同order的buddy块,所以此函数同时接受page_idx和order做为参数。下表给出几个不同的页号在不同的order下的buddy序号。页号0123456789101100000000000001-124816326412825651210242048101-24-81632641282565121024204810012-4816-32-64128256512102420481000124-816-32-64-128-256-51210242048从上表中可以看出,负号表示这个页对应的BUDDY页在此页的前面,正号则表示其BUDDY页在此页的后面。从上表还可以看出,不论输入的页号是否为2的整数倍,其BUDDY页都与其相差2的整数倍。由于此函数只是计算BUDDY页的页面差距,它并不判断这两个页面是否符合BUDDY的条件,因此还需要一个独立的函数来判断这两个页面是否真的互为BUDDY。
要确认两个指定的页面是否互为buddy,可以使用page_is_buddy函数:/** This function checks whether a page is free && is the buddy* we can do coalesce a page and its buddy if* (a) the buddy is not in a hole &&* (b) the buddy is in the buddy system &&* (c) a page and its buddy have the same order &&* (d) a page and its buddy are in the same zone.** For recording whether a page is in the buddy system, we use PG_buddy.* Setting, clearing, and testing PG_buddy is serialized by zone->lock.** For recording page's order, we use page_private(page).*/staticinlineint page_is_buddy(struct page *page, struct page *buddy,int order){if (!pfn_valid_within(page_to_pfn(buddy)))// 恒为falsereturn 0;if (page_zone_id(page) != page_zone_id(buddy))return 0;if (PageBuddy(buddy) && page_order(buddy) == order) {BUG_ON(page_count(buddy) != 0);return 1;}return 0;}在这里PageBuddy用于判断一个页面是否带有PG_buddy标记。注意:在初始化的时候,所有的页面都只有PG_reserved标记。#define PageBuddy(page)test_bit(PG_buddy, &(page)->flags)
在使用BUDDY分配数据之前,必须先明确数据的分配方式,这是通过GFP_xxx一系列的宏定义来控制的。可以将这些宏取或,再将值传递到内存分配函数中。/** GFP bitmasks..** Zone modifiers (see linux/mmzone.h - low three bits)** Do not put any conditional on these. If necessary modify the definitions* without the underscores and use the consistently. The definitions here may* be used in bit comparisons.*/#define __GFP_DMA((__force gfp_t)0x01u)#define __GFP_HIGHMEM((__force gfp_t)0x02u)#define __GFP_DMA32((__force gfp_t)0x04u)/** Action modifiers - doesn't change the zoning** __GFP_REPEAT: Try hard to allocate the memory, but the allocation attempt* _might_ fail.This depends upon the particular VM implementation.** __GFP_NOFAIL: The VM implementation _must_ retry infinitely: the caller* cannot handle allocation failures.** __GFP_NORETRY: The VM implementation must not retry indefinitely.*/#define __GFP_WAIT((__force gfp_t)0x10u)/* Can wait and reschedule? */#define __GFP_HIGH((__force gfp_t)0x20u)/* Should access emergency pools? */#define __GFP_IO((__force gfp_t)0x40u)/* Can start physical IO? */#define __GFP_FS((__force gfp_t)0x80u)/* Can call down to low-level FS? */#define __GFP_COLD((__force gfp_t)0x100u)/* Cache-cold page required */#define __GFP_NOWARN((__force gfp_t)0x200u)/* Suppress page allocation failure warning */#define __GFP_REPEAT((__force gfp_t)0x400u)/* Retry the allocation.Might fail */#define __GFP_NOFAIL((__force gfp_t)0x800u)/* Retry for ever.Cannot fail */#define __GFP_NORETRY((__force gfp_t)0x1000u)/* Do not retry.Might fail */#define __GFP_COMP((__force gfp_t)0x4000u)/* Add compound page metadata */#define __GFP_ZERO((__force gfp_t)0x8000u)/* Return zeroed page on success */#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */#define __GFP_HARDWALL((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */#define __GFP_THISNODE((__force gfp_t)0x40000u)/* No fallback, no policies */#define __GFP_BITS_SHIFT 20/* Room for 20 __GFP_FOO bits */#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))/* if you forget to add the bitmask here kernel will crash, period */#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| /__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| /__GFP_NOFAIL|__GFP_NORETRY|__GFP_COMP| /__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)/* This equals 0, but use constants in case they ever change */#define GFP_NOWAIT(GFP_ATOMIC & ~__GFP_HIGH)/* GFP_ATOMIC means both !wait (__GFP_WAIT not set) and use emergency pool */#define GFP_ATOMIC(__GFP_HIGH)#define GFP_NOIO(__GFP_WAIT)#define GFP_NOFS(__GFP_WAIT | __GFP_IO)#define