感谢支持
我们一直在努力

Linux Kernel 3.0.8 内存管理函数

相关代码如下:


#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实现代码如下,它返回页的虚拟地址


  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. }  


  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. }  


  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


  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


  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. }   

 


  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。


  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)内存申请.


  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


 用于一次内存申请。


  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. 内存释放函数


相关宏定义如下:


  1. #define __free_page(page) __free_pages((page), 0)   

  2. #define free_page(addr) free_pages((addr),0)  

赞(0) 打赏
转载请注明出处:服务器评测 » Linux Kernel 3.0.8 内存管理函数
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏