trace for __get_free_page(转)

转自:http://blog.chinaunix.net/space.php?uid=20286427&do=blog&id=116103

 __get_free_page is a macro, which was defined in  

<include/linux/gfp.h>
>>>
#define __get_free_page(gfp_mask) /
                 __get_free_pages((gfp_mask),0)
>>>
<mm/page_alloc.c>
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{
        struct page *page;

        /*   
         * __get_free_pages() returns a 32-bit address, which cannot represent
         * a highmem page
         */
        VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);

        page = alloc_pages(gfp_mask, order);
        if (!page)
                return 0;
        return (unsigned long) page_address(page);
}

__get_free_pages--->alloc_pages
>>>
include/linux/gfp.h
#ifdef CONFIG_NUMA
extern struct page *alloc_pages_current(gfp_t gfp_mask, unsigned order);

static inline struct page *
alloc_pages(gfp_t gfp_mask, unsigned int order)
{       
        return alloc_pages_current(gfp_mask, order);
}
extern struct page *alloc_page_vma(gfp_t gfp_mask, 
                        struct vm_area_struct *vma, unsigned long addr);
#else   
#define alloc_pages(gfp_mask, order) /
                alloc_pages_node(numa_node_id(), gfp_mask, order)
#define alloc_page_vma(gfp_mask, vma, addr) alloc_pages(gfp_mask, 0)
#endif
#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

__get_free_pages--->alloc_pages---> alloc_pages_node
>>>
include/linux/gfp.h
static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
                                                unsigned int order)
{
        /* Unknown node is current node */
        if (nid < 0)
                nid = numa_node_id();

        return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
}

__get_free_pages--->alloc_pages--->alloc_pages_node--->__alloc_pages
>>>
include/linux/gfp.h
static inline struct page *
__alloc_pages(gfp_t gfp_mask, unsigned int order,
                struct zonelist *zonelist)
{
        return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
}

__get_free_pages--->alloc_pages--->alloc_pages_node--->__alloc_pages---> __alloc_pages_nodemask
>>>
mm/page_alloc.c
/*
 * This is the 'heart' of the zoned buddy allocator.
 */
struct page *
__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
                        struct zonelist *zonelist, nodemask_t *nodemask)
{
        enum zone_type high_zoneidx = gfp_zone(gfp_mask);
        struct zone *preferred_zone;
        struct page *page;
        int migratetype = allocflags_to_migratetype(gfp_mask);

        gfp_mask &= gfp_allowed_mask;

        lockdep_trace_alloc(gfp_mask);

        might_sleep_if(gfp_mask & __GFP_WAIT);

        if (should_fail_alloc_page(gfp_mask, order))
                return NULL;

        /*
         * Check the zones suitable for the gfp_mask contain at least one
         * valid zone. It's possible to have an empty zonelist as a result
         * of GFP_THISNODE and a memoryless node
         */
        if (unlikely(!zonelist->_zonerefs->zone))
                return NULL;

        /* The preferred zone is used for statistics later */
        first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone);
        if (!preferred_zone)
                return NULL;

        /* First allocation attempt */
        page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
                        zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,
                        preferred_zone, migratetype);
        if (unlikely(!page))
                page = __alloc_pages_slowpath(gfp_mask, order,
                                zonelist, high_zoneidx, nodemask,
                                preferred_zone, migratetype);

        trace_mm_page_alloc(page, order, gfp_mask, migratetype);
        return page;
}

>>>
include/linux/gfp.h
get the zone type according to the gfp flags
static inline enum zone_type gfp_zone(gfp_t flags)
{       
        enum zone_type z;
         /*
           #define __GFP_DMA       ((__force gfp_t)0x01u)
          #define __GFP_HIGHMEM   ((__force gfp_t)0x02u)
          #define __GFP_DMA32     ((__force gfp_t)0x04u)
          #define __GFP_MOVABLE   ((__force gfp_t)0x08u)  /* Page is movable */
          #define GFP_ZONEMASK    (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
         */
        int bit = flags & GFP_ZONEMASK;

        z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
                                         ((1 << ZONES_SHIFT) - 1);
        
        if (__builtin_constant_p(bit))
                MAYBE_BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
        else {
#ifdef CONFIG_DEBUG_VM
                BUG_ON((GFP_ZONE_BAD >> bit) & 1);
#endif
        }
        return z;
}

>>>
<include/linux/mm.h>
__get_free_pages--->page_address--->lowmem_page_address
//here we can find the return value is the virtual address of the page
static __always_inline void *lowmem_page_address(struct page *page)
{
        return __va(page_to_pfn(page) << PAGE_SHIFT);
}

__get_free_pages--->page_address--->lowmem_page_address--->page_to_pfn
#define page_to_pfn __page_to_pfn

 #define __page_to_pfn(page)     ((unsigned long)((page) - mem_map) + /
                                  ARCH_PFN_OFFSET)

<mm/memory.c>
struct page *mem_map;  //mem_map is the page array of the whole system.

 

 

另外转一片关于page_to_pfn()和pfn_to_page()的 小文章:

对于结构体指针+、-常数的理解(page_to_pfn和pfn_to_page)

//对同类型的结构体指针进行+,-运算,结果是加减多少个结构体.
//1.对于减运算
//两个同类型的结构体指针进行"-"运算,结果为两个单元地址空间之间一共距离多少个这种结构体
//例:page_to_pfn()函数:将mem_map_t类型的页管理单元page,转换为它所管理的页对应的物理页帧号
#define page_to_pfn(page) (((page) - mem_map) + PHYS_PFN_OFFSET)
//page - mem_map=表示从mem_map到page一共有多少个mem_map_t这种结构体,即:一共有多少个页
//2.对于加运算
//对结构体指针进行"+"运算,如:mem_map + 3;结果为mem_map所在地址加上3个mem_map_t结构体大小结构块之后的最终地址
//例:pfn_to_page()函数:将物理页帧号转换为管理该页的mem_map_t类型指针page
#define pfn_to_page(pfn) ((mem_map + (pfn)) - PHYS_PFN_OFFSET)
//变换一种形式可以更容易理解:(mem_map + (pfn - PHYS_PFN_OFFSET))
//其中index = pfn - PHYS_PFN_OFFSET表示物理页帧号pfn对应的偏移索引号index

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值