読者です 読者をやめる 読者になる 読者になる

buddy allocator: compactionのざっくりとした流れ

kernel linux

__alloc_pages_slowpath()でcompactionの処理をする場合のざっくりとした流れをc⌒っ゚д゚)っφ メモメモ...

__alloc_pages_slowpath()では__alloc_pages_direct_compact()をこのように呼んで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);

__alloc_pages_direct_compact()try_to_compact_pages()を呼んでcompactionを実行し、これまでにも出てきているget_page_from_freelist()を使って空きpageを取得する。

2398         current->flags |= PF_MEMALLOC;
2399         compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
2400                                                 mode, contended_compaction);
2401         current->flags &= ~PF_MEMALLOC;

try_to_compact_pages()は各zoneを順に処理しながらcompactionを行っていく。

1487         /* Compact each zone in the list */
1488         for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
1489                                                                 ac->nodemask) {

といっても、compaction自体はここでは行わず、compact_zone_order()を呼び出してそちらで実施。

1496                 status = compact_zone_order(zone, order, gfp_mask, mode,
1497                                 &zone_contended, alloc_flags,
1498                                 ac->classzone_idx);

compact_zone_order()ではcompaction実施用のデータ設定だけを行い、処理自体はcompact_zone()に任せる。

1432         struct compact_control cc = {
1433                 .nr_freepages = 0,
1434                 .nr_migratepages = 0,
1435                 .order = order,
1436                 .gfp_mask = gfp_mask,
1437                 .zone = zone,
1438                 .mode = mode,
1439                 .alloc_flags = alloc_flags,
1440                 .classzone_idx = classzone_idx,
1441         };
1442         INIT_LIST_HEAD(&cc.freepages);
1443         INIT_LIST_HEAD(&cc.migratepages);
1444 
1445         ret = compact_zone(zone, &cc);

compact_zone()](http://lxr.free-electrons.com/source/mm/compaction.c?v=4.0#L1272)はmigrate_pages()でpageの移動を行う。

1345                 err = migrate_pages(&cc->migratepages, compaction_alloc,
1346                                 compaction_free, (unsigned long)cc, cc->mode,
1347                                 MR_COMPACTION);

pageのmigrationが終わったらまたtry_to_compact_pages()に戻ってくる。 そして、compactionによって十分な空きpageができていたら、compactionを後でやるとなっていたzoneのcompactionを取り止めて、ループを終了する。

1506                 /* If a normal allocation would succeed, stop compacting */
1507                 if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
1508                                         ac->classzone_idx, alloc_flags)) {

compactionしたけどまだ空きpageが足りない場合は次のzoneにとりかかる。