2013年01月08日
情報科学類 オペレーティングシステム II
筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2012/2013-01-08
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
![struct page page[]、物理メモリ](images/struct-page-page.png)
図? struct page page[]による物理メモリの管理
注意: 物理メモリを読み書きするには、論理アドレスが必要だが、論理アドレ スがない(カーネル空間にマップされていない)こともある。
linux-3.6.8/include/linux/mm_types.h
41: struct page {
...
43: unsigned long flags;
...
45: struct address_space *mapping;
...
110: atomic_t _count;
...
117: struct list_head lru;
...
165: void *virtual;
179: }
...
187: ;
| PG_locked | ページがピン留めされている。ページアウトされない。入出力の処理中に設定され、完了後に解除される。 |
| PG_error | このページに対して入出力エラーが生じた。 |
| PG_referenced | ディスク入出力のために参照されている。 |
| PG_uptodate | ページの内容が有効である。入力処理が完了した。 |
| PG_dirty | ページの内容が変更された。 |
| PG_lru | ページングのための LRU リストにある。 |
| PG_active | ページがアクティブである。 |
| PG_slab | スラブ・アロケータで割り当てられた。 |
| PG_arch_1 | アーキテクチャ固有のページ状態 |
| PG_reserved | ページアウト禁止、または、ブード時のメモリ・アロケータで割り当てられた |
| PG_writeback | 書き戻し中 |
| PG_compound | 複合ページ |
| PG_reclaim | 開放すべきページ |
linux-3.6.8/arch/x86/include/asm/page_types.h 8: #define PAGE_SHIFT 12 9: #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) linux-3.6.8/include/linux/const.h 19: #define __AC(X,Y) (X##Y) 20: #define _AC(X,Y) __AC(X,Y)
よく使われるゾーンの種類。

図? メモリのゾーンへの分割
次のような手続きで、メモリを開放する。
linux-3.6.8/include/linux/gfp.h 332: static inline struct page * 333: alloc_pages(gfp_t gfp_mask, unsigned int order) 352: extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); 353: extern unsigned long get_zeroed_page(gfp_t gfp_mask); 366: extern void __free_pages(struct page *page, unsigned int order); 367: extern void free_pages(unsigned long addr, unsigned int order); 372: #define free_page(addr) free_pages((addr), 0)
__get_free_pages(), alloc_pages(), alloc_page() や、 後述する kmalloc() では、 gfp_t のフラグ(gfp_mask) として、次のものがよく使われる。特に GFP_KERNEL がよく使われる。gfp は、get free pages に由来する。
linux-3.6.8/include/linux/gfp.h
| 型 | 説明 |
|---|---|
| GFP_ATOMIC | 高優先度。スリープ不可。割込み処理の前半(割り込みハンドラ、top half)や後半(bottom half)で使う。 |
| GFP_NOIO | スリープ可、入出力不可。 |
| GFP_NOFS | スリープ化、入出力可、ファイル操作不可。ファイルシステムの実装で使う(他のファイルシステムの操作を開始しない)。 |
| GFP_KERNEL | カーネル用メモリ通常の方法。スリープ可。ユーザ・プロセスのコンテキストで使う。 |
| GFP_USER | ユーザ空間用のメモリの通常の方法。スリープ可。 |
| GFP_HIGHUSER | HIGHMEMゾーンからの割当て。スリープ可。 |
| GFP_DMA | DMAゾーンからの割当て。デバイス・ドライバ等が使う。 |

図1(a) Buddyシステムによる空きページの管理(論理的な見方)

図1(b) Buddyシステムによる空きページの管理(線形な見方)
% cat /proc/buddyinfo
Node 0, zone DMA 6 5 3 3 4 2 2 0 1 1 2
Node 0, zone Normal 476 2577 990 354 174 104 65 34 19 1 135
Node 0, zone HighMem 1416 2920 1718 1082 933 504 251 152 87 43 53
%
この例では、DMA ゾーンの 2 0 (4KB) に、6 個、
2 1 (8KB) に、5 個、・・・、2 10 に2個の空きがある。
外部フラグメンテーションが起きると、大きな塊が少なくなる。
void *kmalloc(size_t size, gfp_t flags)引数
| 状況 | フラグ |
| プロセスのコンテキスト、スリープ可能 | GFP_KERNEL |
| プロセスのコンテキスト、スリープ不可 | GFP_ATOMIC |
| 割込みハンドラ | GFP_ATOMIC |
| 割込みハンドラ後半(Softirq,Tasklet,後述) | GFP_ATOMIC |
| DMA可能なメモリ、スリープ可能 | GFP_DMA|GFP_KERNEL |
| DMA可能なメモリ、スリープ不可 | GFP_DMA|GFP_ATOMIC |
void kfree(const void *objp)C言語のユーザ空間で使えるライブラリ free() と似ている。 kmalloc() で割り当てたメモリを解放する。

図? フリーリストの例
オブジェクトは、1ページに2個入る。 オブジェクトが次の順番で開放された。
図? フリーリストの例(ページを意識)
object 2 と object 3 の部分は、1ページ空いている。
図? ページ・フレーム、スラブ、オブジェクトの関係
struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
unsigned long flags, void (*ctor)(void *))
引数
void kmem_cache_destroy(struct kmem_cache *c)kmem_cache_create() で割り当てた struct kmem_cache *を開放する。 shutdown (電源を切る操作)で呼ばれることがある。
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) void *kmem_cache_alloc_node(struct kmem_cache *cachep,gfp_t flags, int node) void kmem_cache_free(struct kmem_cache *cachep, void *b)生成した struct kmem_cache *を使ってオブジェクトのメモリを割り当てる。 割り当てたオブジェクトのメモリは、kmem_cache_free()で開放する。
kmem_cache_alloc_node() は、メモリ・アクセスが不均質なマルチプロセッサ 用。メモリを割り当てるという働きは、kmem_cache_alloc() と同じ。ただし、 node で指定されたプロセッサで高速にアクセスできるメモリに割り当てられる。
linux-3.6.8/kernel/fork.c
122: static struct kmem_cache *task_struct_cachep;
...
251: void __init fork_init(unsigned long mempages)
252: {
...
258: task_struct_cachep =
259: kmem_cache_create("task_struct", sizeof(struct task_struct),
260: ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);
...
283: }
...
124: static inline struct task_struct *alloc_task_struct_node(int node)
125: {
126: return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node);
127: }
128:
129: static inline void free_task_struct(struct task_struct *tsk)
130: {
131: kmem_cache_free(task_struct_cachep, tsk);
132: }
% cat /proc/slabinfo
slabinfo - version: 2.0
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <batchcount> <limit> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
ip_conntrack_expect 0 0 256 15 1 : tunables 120 60 8 : slabdata 0 0 0
ip_conntrack 22 50 384 10 1 : tunables 54 27 8 : slabdata 5 5 0
nfs_direct_cache 0 0 68 58 1 : tunables 120 60 8 : slabdata 0 0 0
nfs_write_data 36 42 512 7 1 : tunables 54 27 8 : slabdata 6 6 0
...
task_struct 84 115 1408 5 2 : tunables 24 12 8 : slabdata 23 23 0
anon_vma 767 1130 16 226 1 : tunables 120 60 8 : slabdata 5 5 0
pgd 54 238 32 119 1 : tunables 120 60 8 : slabdata 2 2 0
pmd 123 123 4096 1 1 : tunables 24 12 8 : slabdata 123 123 0
size-131072(DMA) 0 0 131072 1 32 : tunables 8 4 0 : slabdata 0 0 0
size-131072 0 0 131072 1 32 : tunables 8 4 0 : slabdata 0 0 0
size-65536(DMA) 0 0 65536 1 16 : tunables 8 4 0 : slabdata 0 0 0
size-65536 2 2 65536 1 16 : tunables 8 4 0 : slabdata 2 2 0
...
size-32 8314 8925 32 119 1 : tunables 120 60 8 : slabdata 75 75 0
kmem_cache 150 150 256 15 1 : tunables 120 60 8 : slabdata 10 10 0
%
スラブ・アロケータには、2種類ある。
size-番号 。
DMA が付いているものは、DMA 可能なメモリ。
struct s1 *p; p = malloc( sizeof(struct s1) ); use( p ); free( p );このプログラムを、カーネル内で動かすことを想定してkmalloc() と kfree() を使って書き換えなさい。ただし、gfp のフラグとしては、GFP_KERNEL を使いなさい。
利用 struct s1 *p; /*回答*/ use( p ); /*回答*/
初期化 /*回答*/ 利用 struct s1 *p; /*回答*/ use( p ); /*回答*/