在介绍__alloc_pages前不得不提一下:
UNIX操作系统简单而一致,但只有天才才能领会并欣赏其简单性。
----Dennis Ritchie
我们疯了,你也一样;
__alloc_pages被称为伙伴系统的心脏,同时他也是linux最为冗长的几个函数
之一。
在正式读这个函数之前,我们把相应的辅助函数说明一下:
888 static struct page *
889 get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
890 struct zonelist *zonelist, int alloc_flags)
891 {
892 struct zone **z = zonelist->zones;
893 struct page *page = NULL;
894 int classzone_idx = zone_idx(*z);
895
896 /*
897 * Go through the zonelist once, looking for a zone with enough free.
898 * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
899 */
900 do {
901 if ((alloc_flags & ALLOC_CPUSET) &&
902 !cpuset_zone_allowed(*z, gfp_mask))
903 continue;
904
905 if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
906 unsigned long mark;
907 if (alloc_flags & ALLOC_WMARK_MIN)
908 mark = (*z)->pages_min;
909 else if (alloc_flags & ALLOC_WMARK_LOW)
910 mark = (*z)->pages_low;
911 else
912 mark = (*z)->pages_high;
913 if (!zone_watermark_ok(*z, order, mark,
914 classzone_idx, alloc_flags))
915 if (!zone_reclaim_mode ||
916 !zone_reclaim(*z, gfp_mask, order))
917 continue;
918 }
919
920 page = buffered_rmqueue(zonelist, *z, order, gfp_mask);
921 if (page)
922 break;
923 } while (*(++z) != NULL);
924 return page;
925 }
这个函数在__alloc_pages中被反复调用:他遍历各个管理区(ZONE_DMA,ZONE_DMA32,ZONE_NORMAL,ZONE_HIGHMEM),
并根据相应的mark(水位线值)进行空闲页框的分配工作(实际上是调用buffered_rmqueue进行分配。)这个函数中还调用了一个
比较重要的函数zone_watermark_ok,这个函数检查伙伴系统中有否有满足要求的连续空闲页数可以分配。在此,不得不说明一下
水位线(watermark)的概念。
在这值规定了系统中的内存量必须维持在这个水位之上:好比水杯里的水,你喝过一口之后,剩下的不能小于某个刻度线(水位线)。
那么,这个水位线由谁规定的呢?OK,zone_watermark_ok does it!
857 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
/* */
858 int classzone_idx, int alloc_flags)
859 {
860 /* 该区中现在空闲的页面总数减去要分配出去的页面,free_pages变成负数也没有关系 */
861 long min = mark, free_pages = z->free_pages - (1 << order) + 1;
862 int o;
863 //如果设置了ALLOC_HIGH标志,水位线变成原来的一半,你能喝的水变多。
864 if (alloc_flags & ALLOC_HIGH)
865 min -= min / 2;
//如果设置了ALLOC_HARDER,进一步的降低水位线
866 if (alloc_flags & ALLOC_HARDER)
867 min -= min / 4;
868
//如果分配过后剩余的页面数小于水位线,也就是说你这次要拿走的内存多于我想过你的内存
//返回0
869 if (free_pages <= min + z->lowmem_reserve[classzone_idx])
870 return 0;
//到这里说明了,分配后剩下的页面数是大于水位线值的
//但是,有一点需要考虑:是否这些可用的内存是出自于低阶的
//链表中,例如:所请求的order=5 分配连续内存页框数为32
//此时,系统的free_pages有可能全部来源于order=0,1,2,3,4阶的
//页面,这个情况要排除出去
871 for (o = 0; o < order; o++) {
872 /* At the next order, this order's pages become unavailable */
873 free_pages -= z->free_area[o].nr_free << o;
874
875 /* Require fewer higher order pages to be free */
876 min >>= 1;
877
878 if (free_pages <= min)
879 return 0;
880 }
881 return 1;
每个zone中的描述符中都有三个字段:
pages_low:
pages_min;
pages_high;
这三个字段规定了该区中剩余的空闲内存量应该维持在什么水平。
(待续)
阅读(3147) | 评论(1) | 转发(0) |