本帖最后由 极致Linux内核 于 2023-2-3 20:37 编辑
/*
*get_page_from_freelist goes through the zonelist trying to allocate
* a page.
*/
static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned intorder, int alloc_flags,
conststruct alloc_context *ac)
{
structzoneref *z = ac->preferred_zoneref;
structzone *zone;
boolfair_skipped = false;
boolapply_fair = (alloc_flags & ALLOC_FAIR);
zonelist_scan:
/*
* Scan zonelist, looking for a zone withenough free.
* See also __cpuset_node_allowed() comment inkernel/cpuset.c.
*/
for_next_zone_zonelist_nodemask(zone,z, ac->zonelist, ac->high_zoneidx,
ac->nodemask){
structpage *page;
unsignedlong mark;
if(cpusets_enabled() &&
(alloc_flags& ALLOC_CPUSET) &&
!__cpuset_zone_allowed(zone,gfp_mask))
continue;
/*
* Distribute pages in proportion to theindividual
* zone size to ensure fair page aging. The zone a
* page was allocated in should have no effecton the
* time the page has in memory before beingreclaimed.
*/
if(apply_fair) {
if(test_bit(ZONE_FAIR_DEPLETED, &zone->flags)) {
fair_skipped= true;
continue;
}
if(!zone_local(ac->preferred_zoneref->zone, zone)) {
if(fair_skipped)
gotoreset_fair;
apply_fair= false;
}
}
/*
* When allocating a page cache page forwriting, we
* want to get it from a zone that is withinits dirty
* limit, such that no single zone holds morethan its
* proportional share of globally allowed dirtypages.
* The dirty limits take into account thezone's
* lowmem reserves and high watermark so thatkswapd
* should be able to balance it without havingto
* write pages from its LRU list.
*
* This may look like it could increasepressure on
* lower zones by failing allocations in higherzones
* before they are full. But the pages that do spill
* over are limited as the lower zones areprotected
* by this very same mechanism. It should not become
* a practical burden to them.
*
* XXX: For now, allow allocations topotentially
* exceed the per-zone dirty limit in theslowpath
* (spread_dirty_pages unset) before going intoreclaim,
* which is important when on a NUMA setup theallowed
* zones are together not big enough to reachthe
* global limit. The proper fix for these situations
* will require awareness of zones in the
* dirty-throttling and the flusher threads.
*/
if(ac->spread_dirty_pages && !zone_dirty_ok(zone))
continue;
mark= zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
if(!zone_watermark_fast(zone, order, mark,
ac_classzone_idx(ac), alloc_flags)) {
intret;
/*Checked here to keep the fast path fast */
BUILD_BUG_ON(ALLOC_NO_WATERMARKS< NR_WMARK);
if(alloc_flags & ALLOC_NO_WATERMARKS)
gototry_this_zone;
if(zone_reclaim_mode == 0 ||
!zone_allows_reclaim(ac->preferred_zoneref->zone, zone))
continue;
ret= zone_reclaim(zone, gfp_mask, order);
switch(ret) {
caseZONE_RECLAIM_NOSCAN:
/*did not scan */
continue;
caseZONE_RECLAIM_FULL:
/*scanned but unreclaimable */
continue;
default:
/*did we reclaim enough */
if(zone_watermark_ok(zone, order, mark,
ac_classzone_idx(ac),alloc_flags))
gototry_this_zone;
continue;
}
}
try_this_zone:
page= buffered_rmqueue(ac->preferred_zoneref->zone, zone, order,
gfp_mask,alloc_flags, ac->migratetype);
if(page) {
prep_new_page(page,order, gfp_mask, alloc_flags);
/*
* If this is a high-order atomic allocationthen check
* if the pageblock should be reserved for thefuture
*/
if(unlikely(order && (alloc_flags & ALLOC_HARDER)))
reserve_highatomic_pageblock(page,zone, order);
returnpage;
}
}
/*
* The first pass makes sure allocations arespread fairly within the
* local node. However, the local node might have free pages left
* after the fairness batches are exhausted,and remote zones haven't
* even been considered yet. Try once more without fairness, and
* include remote zones now, before enteringthe slowpath and waking
* kswapd: prefer spilling to a remote zoneover swapping locally.
*/
if(fair_skipped) {
reset_fair:
apply_fair= false;
fair_skipped= false;
reset_alloc_batches(ac->preferred_zoneref->zone);
z =ac->preferred_zoneref;
gotozonelist_scan;
}
returnNULL;
}
原文作者:星空探索
原文链接:https://blog.csdn.net/sunlei0625/article/details/54991365(版权归原文作者所有,侵权联系删除)