Kernel 3.0.8 内存管理函数【转】

转自:http://blog.csdn.net/myarrow/article/details/7208777

1. 内存分配函数

相关代码如下:

#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)
#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

#define __get_free_page(gfp_mask)   __get_free_pages((gfp_mask),0)
#define __get_dma_pages(gfp_mask, order)   __get_free_pages((gfp_mask) | GFP_DMA,(order))

 #define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET))
#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET)
#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))

#define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT))
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)

#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)

 


1)__get_free_pages实现代码如下,它返回页的虚拟地址:

[cpp] view plaincopy
 
  1. unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)  
  2. {  
  3.     struct page *page;  
  4.   
  5.     /* 
  6.      * __get_free_pages() returns a 32-bit address, which cannot represent 
  7.      * a highmem page 
  8.      */  
  9.     VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);  
  10.   
  11.     page = alloc_pages(gfp_mask, order);  
  12.     if (!page)  
  13.         return 0;  
  14.     return (unsigned long) page_address(page);  
  15. }  

 

[cpp] view plaincopy
 
  1. /** 
  2.  * page_address - get the mapped virtual address of a page 
  3.  * @page: &struct page to get the virtual address of 
  4.  * 
  5.  * Returns the page's virtual address. 
  6.  */  
  7. void *page_address(struct page *page)  
  8. {  
  9.     unsigned long flags;  
  10.     void *ret;  
  11.     struct page_address_slot *pas;  
  12.   
  13.     if (!PageHighMem(page))  
  14.         return lowmem_page_address(page);  
  15.   
  16.     pas = page_slot(page);  
  17.     ret = NULL;  
  18.     spin_lock_irqsave(&pas->lock, flags);  
  19.     if (!list_empty(&pas->lh)) {  
  20.         struct page_address_map *pam;  
  21.   
  22.         list_for_each_entry(pam, &pas->lh, list) {  
  23.             if (pam->page == page) {  
  24.                 ret = pam->virtual;  
  25.                 goto done;  
  26.             }  
  27.         }  
  28.     }  
  29. done:  
  30.     spin_unlock_irqrestore(&pas->lock, flags);  
  31.     return ret;  
  32. }  

 

[cpp] view plaincopy
 
  1. static __always_inline void *lowmem_page_address(struct page *page)  
  2. {  
  3.     return __va(PFN_PHYS(page_to_pfn(page)));  
  4. }  

 


2)alloc_pages_node

[cpp] view plaincopy
 
  1. static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,  
  2.                         unsigned int order)  
  3. {  
  4.     /* Unknown node is current node */  
  5.     if (nid < 0)  
  6.         nid = numa_node_id();  
  7.   
  8.     return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));  
  9. }  

参数nid是要分配内存的 NUMA节点 ID,
参数gfp_mask是 GFP_分配标志,
参数order是分配内存的大小(2^order个页面).
返回值是一个指向第一个(可能返回多个页)page结构的指针,失败时返回NULL。
 

[cpp] view plaincopy
 
  1. static inline struct page *  
  2. __alloc_pages(gfp_t gfp_mask, unsigned int order,  
  3.         struct zonelist *zonelist)  
  4. {  
  5.     return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);  
  6. }  

 

[cpp] view plaincopy
 
  1. /* 
  2.  * This is the 'heart' of the zoned buddy allocator. 
  3.  */  
  4. struct page *  
  5. __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,  
  6.             struct zonelist *zonelist, nodemask_t *nodemask)  
  7. {  
  8.     enum zone_type high_zoneidx = gfp_zone(gfp_mask);  
  9.     struct zone *preferred_zone;  
  10.     struct page *page;  
  11.     int migratetype = allocflags_to_migratetype(gfp_mask);  
  12.   
  13.     gfp_mask &= gfp_allowed_mask;  
  14.   
  15.     lockdep_trace_alloc(gfp_mask);  
  16.   
  17.     might_sleep_if(gfp_mask & __GFP_WAIT);  
  18.   
  19.     if (should_fail_alloc_page(gfp_mask, order))  
  20.         return NULL;  
  21.   
  22.     /* 
  23.      * Check the zones suitable for the gfp_mask contain at least one 
  24.      * valid zone. It's possible to have an empty zonelist as a result 
  25.      * of GFP_THISNODE and a memoryless node 
  26.      */  
  27.     if (unlikely(!zonelist->_zonerefs->zone))  
  28.         return NULL;  
  29.   
  30.     get_mems_allowed();  
  31.     /* The preferred zone is used for statistics later */  
  32.     first_zones_zonelist(zonelist, high_zoneidx,  
  33.                 nodemask ? : &cpuset_current_mems_allowed,  
  34.                 &preferred_zone);  
  35.     if (!preferred_zone) {  
  36.         put_mems_allowed();  
  37.         return NULL;  
  38.     }  
  39.   
  40.     /* First allocation attempt */  
  41.     page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,  
  42.             zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,  
  43.             preferred_zone, migratetype);  
  44.     if (unlikely(!page))  
  45.         page = __alloc_pages_slowpath(gfp_mask, order,  
  46.                 zonelist, high_zoneidx, nodemask,  
  47.                 preferred_zone, migratetype);  
  48.     put_mems_allowed();  
  49.   
  50.     trace_mm_page_alloc(page, order, gfp_mask, migratetype);  
  51.     return page;  
  52. }  

其接下来的主要调用流程如下:

get_page_from_freelist->

buffered_rmqueue

3) buffered_rmqueue

     从区域zone中获取一块大小为2^order的物理内存块,返回该内存块的首个页框的描述符page。

 

[cpp] view plaincopy
 
  1. static inline  
  2. struct page *buffered_rmqueue(struct zone *preferred_zone,  
  3.             struct zone *zone, int order, gfp_t gfp_flags,  
  4.             int migratetype)  
  5. {  
  6.     unsigned long flags;  
  7.     struct page *page;  
  8.     int cold = !!(gfp_flags & __GFP_COLD);  
  9.   
  10. again:  
  11.     if (likely(order == 0)) { //获取一页物理内存(2^0),从当前cpu的高速缓存内存中申请  
  12.         struct per_cpu_pages *pcp;  
  13.         struct list_head *list;  
  14.   
  15.         local_irq_save(flags);  
  16.         pcp = &this_cpu_ptr(zone->pageset)->pcp; //获取zone的当前处理器的高速缓存内存描述结构指针  
  17.         list = &pcp->lists[migratetype];  
  18.         if (list_empty(list)) { //高速缓存内存为空  
  19.             pcp->count += rmqueue_bulk(zone, 0,//调用此函数从伙伴系统中分配batch空闲内存到高速缓存内存中  
  20.                     pcp->batch, list,  
  21.                     migratetype, cold);  
  22.             if (unlikely(list_empty(list)))  
  23.                 goto failed;  
  24.         }  
  25.                    //我们从pcp->list链表开始的第一个lru起,去寻找相应的struct page结构体  
  26.         if (cold)  
  27.             page = list_entry(list->prev, struct page, lru);  
  28.         else  
  29.             page = list_entry(list->next, struct page, lru);  
  30.                   //由于被分配出去了,所以高速缓存内存中不再包含这页内存,所以从链表里删除这一项。  
  31.         list_del(&page->lru);  
  32.         pcp->count--;  //相应的当前页数也要减少  
  33.     } else { //获取一块物理内存(2^order)  
  34.         if (unlikely(gfp_flags & __GFP_NOFAIL)) {  
  35.             /* 
  36.              * __GFP_NOFAIL is not to be used in new code. 
  37.              * 
  38.              * All __GFP_NOFAIL callers should be fixed so that they 
  39.              * properly detect and handle allocation failures. 
  40.              * 
  41.              * We most definitely don't want callers attempting to 
  42.              * allocate greater than order-1 page units with 
  43.              * __GFP_NOFAIL. 
  44.              */  
  45.             WARN_ON_ONCE(order > 1);  
  46.         }  
  47.         spin_lock_irqsave(&zone->lock, flags);  
  48.         page = __rmqueue(zone, order, migratetype); //调用函数申请内存  
  49.         spin_unlock(&zone->lock);  
  50.         if (!page)  
  51.             goto failed;  
  52.         __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order));  
  53.     }  
  54.   
  55.     __count_zone_vm_events(PGALLOC, zone, 1 << order);  
  56.     zone_statistics(preferred_zone, zone, gfp_flags);  
  57.     local_irq_restore(flags);  
  58.   
  59.     VM_BUG_ON(bad_range(zone, page));  
  60.     if (prep_new_page(page, order, gfp_flags))  
  61.         goto again;  
  62.     return page; //返回申请到的内存空间的首页内存页的struct page结构指针  
  63.   
  64. failed:  
  65.     local_irq_restore(flags);  
  66.     return NULL;  
  67. }  

4) rmqueue_bulk

 用于多次(count)内存申请.

[cpp] view plaincopy
 
  1. /*  
  2.  * Obtain a specified number of elements from the buddy allocator, all under 
  3.  * a single hold of the lock, for efficiency.  Add them to the supplied list. 
  4.  * Returns the number of new pages which were placed at *list. 
  5.  */  
  6. static int rmqueue_bulk(struct zone *zone, unsigned int order,   
  7.             unsigned long count, struct list_head *list,  
  8.             int migratetype, int cold)  
  9. {  
  10.     int i;  
  11.       
  12.     spin_lock(&zone->lock);  
  13.     for (i = 0; i < count; ++i) {  
  14.         struct page *page = __rmqueue(zone, order, migratetype);  
  15.         if (unlikely(page == NULL))  
  16.             break;  
  17.   
  18.         /* 
  19.          * Split buddy pages returned by expand() are received here 
  20.          * in physical page order. The page is added to the callers and 
  21.          * list and the list head then moves forward. From the callers 
  22.          * perspective, the linked list is ordered by page number in 
  23.          * some conditions. This is useful for IO devices that can 
  24.          * merge IO requests if the physical pages are ordered 
  25.          * properly. 
  26.          */  
  27.         if (likely(cold == 0))  
  28.             list_add(&page->lru, list);  
  29.         else  
  30.             list_add_tail(&page->lru, list);  
  31.         set_page_private(page, migratetype);  
  32.         list = &page->lru;  
  33.     }  
  34.     __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));  
  35.     spin_unlock(&zone->lock);  
  36.     return i;  
  37. }  

 

  

5) __rmqueue

 用于一次内存申请。

[cpp] view plaincopy
 
  1. /* 
  2.  * Do the hard work of removing an element from the buddy allocator. 
  3.  * Call me with the zone->lock already held. 
  4.  */  
  5. static struct page *__rmqueue(struct zone *zone, unsigned int order,  
  6.                         int migratetype)  
  7. {  
  8.     struct page *page;  
  9.   
  10. retry_reserve:  
  11.     page = __rmqueue_smallest(zone, order, migratetype);  
  12.   
  13.     if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {  
  14.         page = __rmqueue_fallback(zone, order, migratetype);  
  15.   
  16.         /* 
  17.          * Use MIGRATE_RESERVE rather than fail an allocation. goto 
  18.          * is used because __rmqueue_smallest is an inline function 
  19.          * and we want just one call site 
  20.          */  
  21.         if (!page) {  
  22.             migratetype = MIGRATE_RESERVE;  
  23.             goto retry_reserve;  
  24.         }  
  25.     }  
  26.   
  27.     trace_mm_page_alloc_zone_locked(page, order, migratetype);  
  28.     return page;  
  29. }  

 

 

 

2. 内存释放函数

相关宏定义如下:

[cpp] view plaincopy
 
    1. #define __free_page(page) __free_pages((page), 0)  
    2. #define free_page(addr) free_pages((addr),0)  
posted @ 2015-09-25 09:46  Sky&Zhang  阅读(469)  评论(0编辑  收藏  举报