机缘巧合,最近研究了一下linux内核__zone_watermark_ok函数,发现高版本(4.4)和低版本3.14之前有所区别,特此记录一下。
先上3.14版本的代码
/*
* Return true if free pages are above 'mark'. This takes into account the order
* of the allocation.
*/
static bool __zone_watermark_ok(struct zone *z, unsigned int order,
unsigned long mark, int classzone_idx, int alloc_flags,
long free_pages)
{
/* free_pages my go negative - that's OK */
long min = mark;
int o;
long free_cma = 0;
free_pages -= (1 << order) - 1;
if (alloc_flags & ALLOC_HIGH)
min -= min / 2;
if (alloc_flags & ALLOC_HARDER)
min -= min / 4;
首先根据传进来的标志位判断是否要将水线降低,然后进行第一次水线判断
#ifdef CONFIG_CMA
/* If allocation can't use CMA areas don't use free CMA pages */
if (!(alloc_flags & ALLOC_CMA))
free_cma = zone_page_state(z, NR_FREE_CMA_PAGES);
#endif
if (free_pages - free_cma <= min + z->lowmem_reserve[classzone_idx])
return false;
使用空闲page总数去比较水线与保留内存的和,如果空闲内存较小,返回false,表示内存水位不足。
若第一次水线判断成功,接下来进行第二次判断:
for (o = 0; o < order; o++) {
/* At the next order, this order's pages become unavailable */
free_pages -= z->free_area[o].nr_free << o;
/* Require fewer higher order pages to be free */
min >>= 1;
if (free_pages <= min)
return false;
}
return true;
}
这个代码一开始看的一脸懵逼,仔细一看,就是在比较free_pages和min变量的值。
每次for循环,都做一次如下操作:
将free_pages减去对应阶数的内存空闲数,并且,将水线降低一半,然后比较二者的大小。
在内存碎片化严重的时候,完全可能出现如下图所示情况,即使空闲内存足够,也会导致水线判断失败
下面上4.4的代码,4.4的代码和3.14只有最后面部分不同。
/* If this is an order-0 request then the watermark is fine */
if (!order)
return true;
/* For a high-order request, check at least one suitable page is free */
for (o = order; o < MAX_ORDER; o++) {
struct free_area *area = &z->free_area[o];
int mt;
if (!area->nr_free)
continue;
for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
if (!list_empty(&area->free_list[mt]))
return true;
}
#ifdef CONFIG_CMA
if ((alloc_flags & ALLOC_CMA) &&
!list_empty(&area->free_list[MIGRATE_CMA])) {
return true;
}
#endif
if (alloc_harder &&
!list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
return true;
}
return false;
首先多了一个判断点,如果申请的order是0,直接返回true。
接下来的循环中,循环体内并不是像3.14一样做减法然后判断,且for循环的起始和终止条件也变了。循环从o=order开始到MAX_ORDER,判断该阶的空闲内存中是否有buddy块,有的话,返回true。这样看起来,好像合理了些~