2011年01月11日
情報科学類 オペレーティングシステム II
筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2010/2011-01-11
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
include/linux/mm_types.h
34: struct page {
35: unsigned long flags; /* Atomic flags, some possibly
36: * updated asynchronously */
37: atomic_t _count; /* Usage count, see below. */
...
48: union {
49: struct {
50: unsigned long private; /* Mapping-private opaque data:
57: struct address_space *mapping; /* If low bit clear, points to
64: };
...
69: struct page *first_page; /* Compound tail pages */
70: };
...
71: union {
72: pgoff_t index; /* Our offset within mapping. */
73: void *freelist; /* SLUB: freelist req. slab lock */
74: };
75: struct list_head lru; /* Pageout list, eg. active_list
...
89: void *virtual; /* Kernel virtual address (NULL if
90: not kmapped, ie. highmem) */
...
103: };
| PG_locked | ページがピン留めされている。ページアウトされない。入出力の処理中に設定され、完了後に解除される。 |
| PG_error | このページに対して入出力エラーが生じた。 |
| PG_referenced | ディスク入出力のために参照されている。 |
| PG_uptodate | ページの内容が有効である。入力処理が完了した。 |
| PG_dirty | ページの内容が変更された。 |
| PG_lru | ページングのための LRU リストにある。 |
| PG_active | ページがアクティブである。 |
| PG_slab | スラブ・アロケータで割り当てられた。 |
| PG_arch_1 | アーキテクチャ固有のページ状態 |
| PG_reserved | ページアウト禁止、または、ブード時のメモリ・アロケータで割り当てられた |
| PG_private | ページの内容が無効(page->private が有効な内容を保持している) |
| PG_writeback | 書き戻し中 |
| PG_compound | 複合ページ |
| PG_reclaim | 開放すべきページ |
よく使われるゾーンの種類。
include/linux/mmzone.h
280: struct zone {
...
284: unsigned long watermark[NR_WMARK];
...
321: struct free_area free_area[MAX_ORDER];
...
391: wait_queue_head_t * wait_table;
392: unsigned long wait_table_hash_nr_entries;
393: unsigned long wait_table_bits;
...
418: const char *name;
419: } ____cacheline_internodealigned_in_smp;
...
158: enum zone_watermarks {
159: WMARK_MIN,
160: WMARK_LOW,
161: WMARK_HIGH,
162: NR_WMARK
163: };
...
23: #ifndef CONFIG_FORCE_MAX_ZONEORDER
24: #define MAX_ORDER 11
25: #else
26: #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
27: #endif
28: #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))
include/linux/gfp.h
302: static inline struct page *
303: alloc_pages(gfp_t gfp_mask, unsigned int order)
304: {
...
306: }
316: extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
314: #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
328: extern void __free_pages(struct page *page, unsigned int order);
329: extern void free_pages(unsigned long addr, unsigned int order);
333: #define free_page(addr) free_pages((addr), 0)
図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_ATOMIC | 高優先度。スリープ不可。割込みハンドラや下半分(bottom half)で使う。 |
| GFP_NOIO | スリープ可、入出力不可。 |
| GFP_NOFS | スリープ化、入出力可、ファイル操作不可。ファイルシステムの実装で使う(他のファイルシステムの操作を開始しない)。 |
| GFP_KERNEL | カーネル用メモリ通常の方法。スリープ可。ユーザ・プロセスのコンテキストで使う。 |
| GFP_USER | ユーザ空間用のメモリの通常の方法。スリープ可。 |
| GFP_HIGHUSER | HIGHMEMゾーンからの割当て。スリープ可。 |
| GFP_DMA | DMAゾーンからの割当て。デバイス・ドライバ等が使う。 |
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)生成した struct kmem_cache *を使ってオブジェクトのメモリを割り当てる。 割り当てたオブジェクトのメモリは、kmem_cache_free()で開放する。
% 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 可能なメモリ。
kernel/fork.c
112: static struct kmem_cache *task_struct_cachep;
...
202: void __init fork_init(unsigned long mempages)
203: {
...
206: #define ARCH_MIN_TASKALIGN L1_CACHE_BYTES
...
209: task_struct_cachep =
210: kmem_cache_create("task_struct", sizeof(struct task_struct),
211: ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);
...
110: # define alloc_task_struct() kmem_cache_alloc(task_struct_cachep, GFP_KERNEL)
111: # define free_task_struct(tsk) kmem_cache_free(task_struct_cachep, (tsk))
mm/slab.c
200: struct slab {
201: struct list_head list;
202: unsigned long colouroff;
203: void *s_mem; /* including colour offset */
204: unsigned int inuse; /* num of objs active in slab */
205: kmem_bufctl_t free;
...
207: };
図? ページ・フレーム、スラブ、オブジェクトの関係
mm/slab.c
269: struct kmem_list3 {
270: struct list_head slabs_partial; /* partial list first, better asm code */
271: struct list_head slabs_full;
272: struct list_head slabs_free;
...
281: };
スラブの分類
図? スラブのリスト
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 ); /*回答*/