Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2159514
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-11-16 11:56:58

一.总体说明
1.1 关于struct page的说明
  1. typedef struct page {
  2.     struct list_head list;             /* ->mapping has some page lists. */
  3.     struct address_space *mapping;     /* The inode (or ...) we belong to. */
  4.     unsigned long index;               /* Our offset within mapping. */
  5.     struct page *next_hash;            /* Next page sharing our hash bucket in the pagecache hash table. */
  6.     atomic_t count;                    /* Usage count, see below. */
  7.     unsigned long flags;               /* atomic flags, some possibly updated asynchronously */
  8.     struct list_head lru;              /* Pageout list, eg. active_list; protected by pagemap_lru_lock !! */
  9.     wait_queue_head_t wait;            /* Page locked? Stand in line... */
  10.     struct page **pprev_hash;          /* Complement to *next_hash. */
  11.     struct buffer_head * buffers;      /* Buffer maps us to a disk block. */
  12.     void *virtual;                     /* Kernel virtual address (NULL if not kmapped, ie. highmem) */
  13.     struct zone_struct *zone;          /* Memory zone we are in. */
  14. } mem_map_t;


二.代码分析
start_kernel-->kmem_cache_sizes_init-->kmem_cache_create-->kmem_cache_alloc
-->kmem_cache_grow-->kmem_getpages-->__get_free_pages


在linux-2.4.18/include/linux/mm.h:362中
  1. static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
  2. {
  3.     if (order >= MAX_ORDER)    //默认MAX_ORDER=10,所以这儿最多能分配2^9=512个页面2M内存
  4.         return NULL;
  5.     return _alloc_pages(gfp_mask, order);
  6. }


mm/page_alloc.c中
  1. struct page *_alloc_pages(unsigned int gfp_mask, unsigned int order)
  2. {
  3.     return __alloc_pages(gfp_mask, order, contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK));
  4. }

在mm/page_alloc.c中
  1. /*
  2.  * This is the 'heart' of the zoned buddy allocator:
  3.  */
  4. struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)
  5. {
  6.     unsigned long min;
  7.     zone_t **zone, * classzone;
  8.     struct page * page;
  9.     int freed;

  10.     zone = zonelist->zones;        //contig_page_data.node_zonelists中的项
  11.     classzone = *zone;
  12.     min = 1UL << order;            //order=0,1<<0=1,所以要分配的最小的页面是1个
  13. //假设当前是查找zone_normal,如果if(z->free_pages>min)说明normal中空闲pages不足,
  14. //zonelist中nomal的下一项是zone_normal,那么就到zone_dma中去查找
  15.     for (;;) {
  16.         zone_t *z = *(zone++);     
  17.         if (!z)                    //每个zonelist都是以0结尾的
  18.             break;

  19.         min += z->pages_low;        //pages_low=510是zone_balance_max中规定的,所以执行后min=511
  20.         if (z->free_pages > min) {
  21.             page = rmqueue(z, order);
  22.             if (page)
  23.                 return page;
  24.         }
  25.     }

  26.     classzone->need_balance = 1;
  27.     mb();
  28.     if (waitqueue_active(&kswapd_wait))
  29.         wake_up_interruptible(&kswapd_wait);

  30.     zone = zonelist->zones;
  31.     min = 1UL << order;
  32.     for (;;) {
  33.         unsigned long local_min;
  34.         zone_t *z = *(zone++);
  35.         if (!z)
  36.             break;

  37.         local_min = z->pages_min;
  38.         if (!(gfp_mask & __GFP_WAIT))
  39.             local_min >>= 2;
  40.         min += local_min;
  41.         if (z->free_pages > min) {
  42.             page = rmqueue(z, order);
  43.             if (page)
  44.                 return page;
  45.         }
  46.     }

  47.     /* here we're in the low on memory slow path */

  48. rebalance:
  49.     if (current->flags & (PF_MEMALLOC | PF_MEMDIE)) {
  50.         zone = zonelist->zones;
  51.         for (;;) {
  52.             zone_t *z = *(zone++);
  53.             if (!z)
  54.                 break;

  55.             page = rmqueue(z, order);
  56.             if (page)
  57.                 return page;
  58.         }
  59.         return NULL;
  60.     }

  61.     /* Atomic allocations - we can't balance anything */
  62.     if (!(gfp_mask & __GFP_WAIT))
  63.         return NULL;

  64.     page = balance_classzone(classzone, gfp_mask, order, &freed);
  65.     if (page)
  66.         return page;

  67.     zone = zonelist->zones;
  68.     min = 1UL << order;
  69.     for (;;) {
  70.         zone_t *z = *(zone++);
  71.         if (!z)
  72.             break;

  73.         min += z->pages_min;
  74.         if (z->free_pages > min) {
  75.             page = rmqueue(z, order);
  76.             if (page)
  77.                 return page;
  78.         }
  79.     }

  80.     /* Don't let big-order allocations loop */
  81.     if (order > 3)
  82.         return NULL;

  83.     /* Yield for kswapd, and try again */
  84.     current->policy |= SCHED_YIELD;
  85.     __set_current_state(TASK_RUNNING);
  86.     schedule();
  87.     goto rebalance;
  88. }
为什么

在mm/page_alloc.c中__alloc_pages-->rmqueue
  1. static struct page * rmqueue(zone_t *zone, unsigned int order)
  2. {
  3.     free_area_t * area = zone->free_area + order;     //free_area[order]就是free_list中含order个空闲页面的数组
  4.     unsigned int curr_order = order;
  5.     struct list_head *head, *curr;
  6.     unsigned long flags;
  7.     struct page *page;

  8.     spin_lock_irqsave(&zone->lock, flags);
  9.     do {
  10.         head = &area->free_list;
  11.         curr = memlist_next(head);

  12.         if (curr != head) {                                 //curr!=head说明该order的链表不为空
  13.             unsigned int index;

  14.             page = memlist_entry(curr, struct page, list);  //从head的链表中取第1个page返回
  15.             if (BAD_RANGE(zone,page))
  16.                 BUG();
  17.             memlist_del(curr);                              //把curr从head的链表中移除,即链表中不再管理刚分配的page
  18.             index = page - zone->zone_mem_map;
  19.             if (curr_order != MAX_ORDER-1)
  20.                 MARK_USED(index, curr_order, area);
  21.             zone->free_pages -= 1UL << order;               //zone中含有的free_pages减1
  22.     //如果从order的链表中就分配到了page则order==curr_order,下面这个expand里面就直接返回
  23.     //如果从order链表中没有分配到page,则curr_order++之后,curr_order>order则expand中就会执行
  24.             page = expand(zone, page, index, order, curr_order, area);  
  25.             spin_unlock_irqrestore(&zone->lock, flags);

  26.             set_page_count(page, 1);
  27.             if (BAD_RANGE(zone,page))
  28.                 BUG();
  29.             if (PageLRU(page))
  30.                 BUG();
  31.             if (PageActive(page))
  32.                 BUG();
  33.             return page;    
  34.         }
  35.         curr_order++;                                   //curr==head说明该order的链表为空,
  36.         area++;                                         //就到up-level的order中去找 
  37.     } while (curr_order < MAX_ORDER);
  38.     spin_unlock_irqrestore(&zone->lock, flags);

  39.     return NULL;
  40. }
在mm/page_alloc.c中L159 __alloc_pages-->rmqueue-->expand
  1. static inline struct page * expand (zone_t *zone, struct page *page,
  2.      unsigned long index, int low, int high, free_area_t * area)
  3. {
  4.     unsigned long size = 1 << high;
  5. //将8作为order=1的结点插入order=1
  6. //将10作为order=0的结点插入order=0中
  7. //则11就是分配到的page的结点
  8.     while (high > low) {
  9.         if (BAD_RANGE(zone,page))
  10.             BUG();
  11.         area--;
  12.         high--;
  13.         size >>= 1;
  14.         memlist_add_head(&(page)->list, &(area)->free_list);  
  15.         MARK_USED(index, high, area);
  16.         index += size;
  17.         page += size;
  18.     }
  19.     if (BAD_RANGE(zone,page))
  20.         BUG();
  21.     return page;
  22. }

开始时的状态:

第1次alloc_page(order=0)时的状态:

第2次alloc_page(order=0)时的状态:


阅读(1670) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~