内核技术中文网»首页 论坛 圈点 查看内容

0 评论

0 收藏

分享

get_page_from_freelist()函数

本帖最后由 极致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(版权归原文作者所有,侵权联系删除

回复

举报 使用道具

全部回复
暂无回帖,快来参与回复吧
主题 1545
回复 0
粉丝 2
扫码获取每晚技术直播链接
快速回复 返回顶部 返回列表