LinuxのPage Allocatorで __alloc_pages_slowpath()の流れをメモ程度に。 読んでいるカーネルのversionは4.0。
__alloc_pages_nodemask()でget_page_from_freelist()を呼んだ時にpageの確保ができなかった場合に呼ばれるのが __alloc_pages_slowpath()。 get_page_from_freelist()もpageを確保するために色々とやっているけど、それでも失敗した場合の処理なので、いろいろやることが多い。
ここからは実際にコードを見ていきます。 まず、最初のほうで。まず、gfp_maskをチェックして、このnode以外からのpage確保はしないなっていたらpge確保を諦めます。
2633 if (IS_ENABLED(CONFIG_NUMA) && 2634 (gfp_mask & GFP_THISNODE) == GFP_THISNODE) 2635 goto nopage; 2636
次にretryラベルがあり、このラベルは色々と手を尽くしたけどダメだった場合に、リトライするならここにきます。次のgfp_maskのチェックでswapの処理を呼んでも良いとなっていたらkswapdにswapの処理をしてもらいます。
2637 retry: 2638 if (!(gfp_mask & __GFP_NO_KSWAPD)) 2639 wake_all_kswapds(order, ac);
そして、メモリ確保のフラグを再設定します。
2641 /* 2642 * OK, we're below the kswapd watermark and have kicked background 2643 * reclaim. Now things get more complex, so set up alloc_flags according 2644 * to how we want to proceed. 2645 */ 2646 alloc_flags = gfp_to_alloc_flags(gfp_mask);
どのzoneからpageを確保するか決定します。
2648 /* 2649 * Find the true preferred zone if the allocation is unconstrained by 2650 * cpusets. 2651 */ 2652 if (!(alloc_flags & ALLOC_CPUSET) && !ac->nodemask) { 2653 struct zoneref *preferred_zoneref; 2654 preferred_zoneref = first_zones_zonelist(ac->zonelist, 2655 ac->high_zoneidx, NULL, &ac->preferred_zone); 2656 ac->classzone_idx = zonelist_zone_idx(preferred_zoneref); 2657 }
ここでもう一度get_page_from_freelist()を呼んでpageの確保にtryします。この時にalloc_flagsからALLOC_NO_WATERMARKSを外しているので、watermarkを無視しないようにします。。 pageの確保ができればgot_pgラベルに飛びます。
2659 /* This is the last chance, in general, before the goto nopage. */ 2660 page = get_page_from_freelist(gfp_mask, order, 2661 alloc_flags & ~ALLOC_NO_WATERMARKS, ac); 2662 if (page) 2663 goto got_pg;
上記のget_page_from_freelist()でpageの確保に失敗した場合で、alloc_flagsにALLOC_NO_WATERMARKSが立っていた場合は、緊急ということで__alloc_pages_high_priority()を呼んで優先度高としてpageの確保にいき、pageが確保できればgot_pgラベルに飛びます。
2665 /* Allocate without watermarks if the context allows */ 2666 if (alloc_flags & ALLOC_NO_WATERMARKS) { 2667 /* 2668 * Ignore mempolicies if ALLOC_NO_WATERMARKS on the grounds 2669 * the allocation is high priority and these type of 2670 * allocations are system rather than user orientated 2671 */ 2672 ac->zonelist = node_zonelist(numa_node_id(), gfp_mask); 2673 2674 page = __alloc_pages_high_priority(gfp_mask, order, ac); 2675 2676 if (page) { 2677 goto got_pg; 2678 } 2679 } 2680
次のwaitはgfp_mask & GFP_WAITをした結果で、GFP_WAITが立っていない場合は待teないのでpageの確保を諦めます。
2681 /* Atomic allocations - we can't balance anything */ 2682 if (!wait) { 2683 /* 2684 * All existing users of the deprecated __GFP_NOFAIL are 2685 * blockable, so warn of any new users that actually allow this 2686 * type of allocation to fail. 2687 */ 2688 WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL); 2689 goto nopage; 2690 }
次の2つのチェックもフラグを見て諦めるか続けるかを決定します。
692 /* Avoid recursion of direct reclaim */ 2693 if (current->flags & PF_MEMALLOC) 2694 goto nopage; 2695 2696 /* Avoid allocations with no watermarks from looping endlessly */ 2697 if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL)) 2698 goto nopage; 2699
ここまでやってもpageの確保ができていないので、次の手段としてpageのコンパクションを行います。
2700 /* 2701 * Try direct compaction. The first pass is asynchronous. Subsequent 2702 * attempts after direct reclaim are synchronous 2703 */ 2704 page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac, 2705 migration_mode, 2706 &contended_compaction, 2707 &deferred_compaction); 2708 if (page) 2709 goto got_pg;
コンパクションしてもpageが確保できなかったら、次のif文の条件に該当をチェックして、該当する場合は各種フラグのチェックで諦めるかどうか決めます。
2712 if ((gfp_mask & GFP_TRANSHUGE) == GFP_TRANSHUGE) { 〜略〜 2740 }
コンパクションでもダメだったので、次はページの回収を行います。
2751 /* Try direct reclaim and then allocating */ 2752 page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac, 2753 &did_some_progress); 2754 if (page) 2755 goto got_pg;
pageの回収をしてもまだpageの確保にした場合、リトライするかどうか判断します。 リトライする場合、誰かを殺してでもpage確保するということになり、 __alloc_pages_may_oom()が呼ばれます。 これでpageが確保できればgot_pgに飛びます。oomを走らせられない状況だった場合はpage確保を諦めます。pageは確保できなかったけども、oomの処理が動いたならretryラベルに飛んで、また最初から実行し直します。
2757 /* Check if we should retry the allocation */ 2758 pages_reclaimed += did_some_progress; 2759 if (should_alloc_retry(gfp_mask, order, did_some_progress, 2760 pages_reclaimed)) { 2761 /* 2762 * If we fail to make progress by freeing individual 2763 * pages, but the allocation wants us to keep going, 2764 * start OOM killing tasks. 2765 */ 2766 if (!did_some_progress) { 2767 page = __alloc_pages_may_oom(gfp_mask, order, ac, 2768 &did_some_progress); 2769 if (page) 2770 goto got_pg; 2771 if (!did_some_progress) 2772 goto nopage; 2773 } 2774 /* Wait for some write requests to complete then retry */ 2775 wait_iff_congested(ac->preferred_zone, BLK_RW_ASYNC, HZ/50); 2776 goto retry; 2777 } else {
リトライしない場合は、もう一度コンパクションを実行します。これでpageが確保できなかったらwarningを出した後にNULLをreturnして終了です。
2777 } else { 2778 /* 2779 * High-order allocations do not necessarily loop after 2780 * direct reclaim and reclaim/compaction depends on compaction 2781 * being called after reclaim so call directly if necessary 2782 */ 2783 page = __alloc_pages_direct_compact(gfp_mask, order, 2784 alloc_flags, ac, migration_mode, 2785 &contended_compaction, 2786 &deferred_compaction); 2787 if (page) 2788 goto got_pg; 2789 }
と、ざっくりと __alloc_pages_slowpath()のコード・リーディングめもでした。
CANSAY nu board (ヌーボード) A4判 NGA403FN08
- 出版社/メーカー: 欧文印刷
- 発売日: 2015/04/01
- メディア: オフィス用品
- この商品を含むブログを見る