Skip to content

Instantly share code, notes, and snippets.

@nhoriguchi
Last active April 2, 2019 00:18
Show Gist options
  • Save nhoriguchi/04c8661b577277d619d3636faa9d00ff to your computer and use it in GitHub Desktop.
Save nhoriguchi/04c8661b577277d619d3636faa9d00ff to your computer and use it in GitHub Desktop.
Hugetlb Reservation

概要

hugetlbfs の reservation は hugepage を preallocation の管理に使用される。 hugepage は使用前に free hugepage プールを作成し、page fault の際に実際にプロセスに割り当てられるが、preallocation というのはその前段階で mmap() はしたが、まだ fault in はしていない状態を指す。 mmap()MAP_NORESERVE フラグを渡すことによって reserve を回避することもできるが、その場合もし fault in までの間に他のプロセスによって hugepage を割り当てられてしまった場合、page fault に失敗して SEGSERV を受信してしまうことになる。 事前に reserve しておくことによって確実に fault in できるようにする、というのが reserve の基本的な役割と言える。

hugetlb はページサイズごと (x86 だと 2MB 以外に 1GB もサポートしている) のグローバル変数 hstate で管理されていて、その中の resv_huge_pages が reserve カウントを表す。 さらに、hugetlbfs 上のファイルを mmap() する場合は inode に resv_map 構造体を紐付けて reservation とオフセットの対応を管理している。

private マッピングと shared マッピングの場合で resv_map の動作が少し異なるようだ。 private のときは vma->vm_private_data からリンクされ、shared のときは inode->i_mapping->private_data からリンクされる。 shmget() 経由で使用しても内部的には inode が生成されるため、inode 作成時に resv_map 構造体も用意される。 reservation を作成する関数は hugetlb_reserve_pages() である。 private/shared で resv_map の意味が少し異なる。

  • shared の場合、reservation は当該アドレスが予約されているか、既に当該アドレスに紐付けられた hugepage が存在することを意味している。
  • private の場合、当該アドレスに hugepage が割り当てられた (reservation が消費された) 後は reservation は削除される。

resv_map は新しく hugepage を使用するプロセスからの要求を満たすためにいくつ reserve が必要か計算するために使用され、shared の場合に既存の reserve を考慮するために参照される。

subpool という概念がある。 通常 global プールは hugepage の空き容量 (使用可能量の最大値) に関する制御を行うが、subpool はある hugetlbfs マウントごとに最低限使用できる hugepage の数を与えるのに使用される。

resv_map と subpool を見て必要な reservation を計算する。 その延長で hugepage pool を縮小・拡張したりすることもある。 必要な reserve 数を十分みたすだけ free ページがあるならば、その reserve は満たされて resv_map は更新される。

alloc_huge_page() を通して hugepage が実際にプロセスにマップされた段階で reservation は消費される。 vma_needs_reservation() は対象となる vma の指定したアドレスをマッピングするために reservation が必要かどうかを判断するもので、0/1 が返る。 resv_map と subpool に、当該アドレスの reservation が存在するかを問い合わせている。

PagePrivate フラグは当該ページを割り当てる際に reservation が消費されたかどうかを示している。 開放時に reservation を復帰させるかどうかの判断に使用される。 free huge ページが見つからず surplus ページが割り当てられた場合も同様の reservation の処理を行っている。 割り当てられた hugepage の ->private は当該ページに関連付けられた subpool を表している。 reservation が消費されたのち、vma_commit_reservation を用いて resv_map を更新する。 vma_needs_reservation が呼ばれてから vma_commit_reservation に到達するまでの間に他のスレッドが同じ hugepage を割り当てようとして競合することがあるが、vma_commit_reservation 戻り値が vma_needs_reservation のものと同じであると確認することにより競合を検出し、resv_map を正しく更新することができるようになる。

subpool は hugetlbfs をマウントする際に min_size オプションを与えた場合に使用される。 マウント時にグローバルプールから必要数の hugepage を reserve し、必要数に足りない時はマウント時で失敗を通知する。 subpool から hugepage を割り当てようとする場合、hugepage_subpool_get/put_pages() で残数管理を行う。 基本的に hugepage_subpool_get_pages() に必要な hugepage 数を渡して、戻り値として使用できる量が返されるため、両者が等しければ要求数使用できることになる。 戻り値が要求数より小さい場合、そのままでは要求を満たせないため global pool に差分を要求して調整することになる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment