include/linux/gfp.h::alloc_pages() -> alloc_pages_node() -> __alloc_pages_node() -> __alloc_pages() mm/page_alloc.c::__alloc_pages() invokes get_page_from_freelist() mm/page_alloc.c::get_page_from_freelist() invokes rmqueue() mm/page_alloc.c::rmqueue() -> rmqueue_buddy() -> __rmqueue() ends up invoking __rmqueue_smallest() mm/page_alloc.c::__rmqueue_smallest() tries to allocate a fragment of order "order", increasing the allocation order until something is found... Then, it calls expand() to split the allocated memory fragment and insert free buddies in the queues mm/page_alloc.c::expand() splits a fragment of order "high" into smaller fragments (up to "low") and inserts them in the free queues page_address() is implemented in include/linux/mm.h mm/page_alloc.c::__free_pages() -> free_the_page() -> __free_pages_ok() -> __free_one_page() mm/page_alloc.c::__free_one_page() checks if the page's buddy is in free list (find_buddy_page_pfn()), merges the pages (combined_pfn = buddy_pfn & pfn), and repeats at higher orders... mm/internal.h::find_buddy_page_pfn() uses __find_buddy_pfn() which does "page_pfn ^ (1 << order)", than checks if the buddy is free (page_is_buddy()) GFP_* flags are defined in include/linux/gfp_types.h