numaのnodemask構造体
Rev.2を表示中。最新版はこちら。
numaは物理メモリ群を、領域単位で独立したメモリ領域として管理します。この独立したメモリ領域をノードと言い、node_data[]で、そのノード単位のpageを管理しています。このnode_data[]のどのノードを使うとか、どのように使うかは、メモリポリシーとして定義され、タスク/vma領域単位/tmpfsとか物理メモリを取得するエレメント毎に設定されます。
このどのノードを使うのかは、メモリポリシのメンバーstruct nodemask_tにビットマップとして設定しています。tmpfsのmountオプションのノードリストはstruct nodemask_tにビットマップとして設定されるわけです。
struct nodemask_tはstruct { DECLARE_BITMAP(bits, MAX_NUMNODES); }して定義され、要はstruct { unsigned long bits[hoge]; }の単純な構造体です。hogeはノード数に対応した配列数で、longを4バイトとすると、ノード数が30ならbit[1]、ノード数が40ならbit[2]となるわけですが、それをコンパイル時は可変値となる一定値のノード数と言うことで、マクロのみでの実装故、以下のような難しげなコードとなっています。
struct pglist_data *node_data[MAX_NUMNODES]; typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t; #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)]BITS_TO_LONGS(bits)でノード数となるbitsに応じた配列数を求めます。BITS_PER_BYTE * sizeof(long)は配列1つで格納できるノード数です。
#define BITS_PER_BYTE 8 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))DIV_ROUND_UPで配列数を算出します。dは1配列に設定できるノード数で、longを4バイトとすると8×4=32です。要はn/d+(n%d?1: 0)ということです。
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))CONFIG_NODES_SHIFTはカーネルコンパイルオプションで、NODES_SHIFTとなっていますが結果的にノード数になります。1をNODES_SHIFTでシフトする事でMAX_NUMNODESとしているため、NODES_SHIFT=1だとノード数は2で、CONFIG_NODES_SHIFTでない場合、NODES_SHIFT=0でノード数は1となります。これはnumaでないシステムもノード1のnumaとして動作しているという事です。
#ifdef CONFIG_NODES_SHIFT #define NODES_SHIFT CONFIG_NODES_SHIFT #else #define NODES_SHIFT 0 #endif #define MAX_NUMNODES (1 << NODES_SHIFT)