110 likes | 432 Views
■ メモリ i ノード. i ノードにはファイルの管理情報 ( ファイル名以外の全ての情報 ) が納められている。基本的な仕組みは 伝統的な UNIX とほぼ同様である。ここで言う i ノードとは、物理的なディスク上に配置された i ノードの キャッシュとして利用されるメモリ上の i ノードである。 linux の i ノードは最近の UNIX で v ノード (virtual node) と呼ばれているものに相当する。様々な種類のファイル システムのファイルを扱う必要があるため、 i ノードを仮想化したものである。 i ノードに対する操作は、
E N D
■メモリiノード iノードにはファイルの管理情報(ファイル名以外の全ての情報)が納められている。基本的な仕組みは 伝統的なUNIXとほぼ同様である。ここで言うiノードとは、物理的なディスク上に配置されたiノードの キャッシュとして利用されるメモリ上のiノードである。 linuxのiノードは最近のUNIXでvノード(virtual node)と呼ばれているものに相当する。様々な種類のファイル システムのファイルを扱う必要があるため、iノードを仮想化したものである。 iノードに対する操作は、 そのファイルが存在するファイルシステム毎に異なっており、iノード(ファイル)操作方法はそれぞれの iノードの i_op、i_fopに登録されている。また、iノード構造体の下半分は、 unionとなっておりファイル システム固有のデータが格納可能となっている。 ファイル構造はファイルシステム毎に異なっており、 このファイル構造情報はiノードunion領域に存在する。 ext2ファイルシステムではこの領域にファイルを構成する ディスクブロックの配置情報を保持している。 inode i_inv i_dev i_state i_op i_fop Filesystem specific part cleate; lookup; link; mkdir; truncate; …. open; read; write; ioctl; mmap; …. inode_operations file_operations
■メモリiノード - iノードキャッシュ 一度利用したiノードは、直ぐに再利用される可能性が高いためハッシュ構造でキャッシュしている。 また、iノードは頻繁に更新されるが、毎回ディスクまで書き込みに行くと性能的に不利になるため、 一般に遅延書き込みで実現されている。更新はされたが、まだディスク上まで反映されていないiノード は Dirtyの印がつけられた上でスーパブロックのdirtyリストにリンクされ、適当なタイミングで ディスクに 書き戻される。 (kupdateデーモン、sync/umount処理など) ディスク上の値と一致した値を持つiノードは、inode_in_useリストにリンクされている。 利用されていないiノードはフリーリストinode_unusedに繋げられている。伝統的UNIXと異なりhashと フリーリストの両方に継っているという状態は存在しない。
inode_table i_hash i_list i_hash i_list i_hash i_list i_hash i_list : i_hash i_list i_hash i_list i_hash i_list : i_hash i_list i_hash i_list i_hash i_list i_hash i_list : inode_in_use inode_unused s_dirty Super-block
■メモリiノード - メモリiノードの確保 iノード域の確保は、伝統的UNIXと同じigetという関数で実現されている。 igetは指定されたiノード 番号に対応するiノード域を確保し返却する。 iノード域の初期化は各ファイルシステムが行う。 iget(スーパブロック, iノード番号, ...) if(iノードキャッシュ内に目的のiノードが見つかった(find_inode関数)) return 見つかったiノード iノード番号に対応するメモリiノードを作成する(get_new_inode関数) return 新規に作成したiノード キャッシュ内に目的のiノードが見つからなかった場合、以下のget_new_inode関数により、 空のiノード域を確保し初期化を行う。 get_new_inode(iノード番号) iノード域の確保(alloc_inode関数) iノード域をinode_in_useリストに繋ぐ iノード域をキャッシュに登録 iノード初期化 ディスクinode域の読み込み(read_inodeオペレーション) return 拡張したiノード域
■メモリiノード - メモリiノードの解放 利用が終わったiノード域の解放は下記iput関数にて実現されている。 iノード域の解放といっても、 メモリ上から消えてなくなる訳ではなく、 iノード域の参照数を一つ減らすだけである。 参照数が0でも即フリーリストに戻される訳ではなく、フリーリストinode_unusedに戻す候補となるだけ である。 iput(iノード) iノードの参照数を一つ減らす if(参照数が1以上なら) return; if(既にファイルが削除されている) { iノードキャッシュのリンクを切る iノードにリンクされているページキャッシュの解放 ディスク上のiノードの解放(後で詳しく説明) メモリiノード域の解放 } else { inodeをinode_unusedリストに繋ぎ直す。 }
■メモリiノード - メモリiノード領域の解放■メモリiノード - メモリiノード領域の解放 空きメモリ領域が圧迫して来るとshrink_icache_memory関数が呼び出される。 shrink_icache_memory関数は、inode_unusedリストにリンクされているinodeの解放を行う (prune_icache関数、 kmem_cache_shrink関数)。 inodeにページキャッシュがリンクされている場合、そのページの解放も行う (truncate_inode_pages関数)。 この後に述べるディレクトリキャッシュとも連動しており、ディレクトリキャッシュから参照されている間は 解放されない。
■メモリiノード - iノード域の更新 更新したiノード域はディスクに書き戻される必要がある。 mark_inode_dirty関数は、 更新したiノードにDirtyの印を付け、スーパブロックのDirty iノードリストに登録する。 ここに登録されたiノードは、kupdateデーモン、sync/umountシステムコールによりディスクに 書き戻される。
■メモリiノード - その他の主なiノード操作関数■メモリiノード - その他の主なiノード操作関数 find_inode() iノードキャッシュ中からiノード番号で指定されたiノードを検索 alloc_inode() iノード域を新規に確保する destroy_inode() iノード領域を解放する write_inode() メモリiノード域の情報をディスクiノードに書き戻す。 実際は、この関数自体はバッファまでしか書き戻さないので、 その後バッファの フラッシュを行う必要がある。 wait_on_inode() inodeがロックされていたら、その解除を待ち合わせる sync_inodes()、sync_all_inodes()、write_inode_now()関数 iノードをディスクへ書き戻す。
■メモリiノード - iノードの状態遷移 iノードの状態遷移を図にまとめると以下のようになる。 有効な(利用可能な)iノードは全て inode_in_useに繋がれており、書き込みがあったがまだディスクに 反映されていないiノードには I_DIRTYのフラグが立っている。 まさにI/O中のiノードは I_LOCKフラグが立っており、その間に他のプロセスからのアクセスを禁止する。 (ファイルシステムよっては、バッファキャッシュに書き戻すだけの間I_LOCKが立つ)
Super-block S_dirty shrink_icache_memory() make_inode_dirty() NULL I_DIRTY FREE sync_one() finished sync_one() start get_new_inode() finished I_LOCK I_LOCK write_inode() read_inode() get_new_inode() start Buffer cache I_LOCK allock_inode()
■メモリiノード - iノード状態の監視 以下の変数を見る事により、iノードの状態を大雑把につかむことができる。 v2.2と異なり、得られる情報は少ない。 inodes_stat メンバ nr_unusedは、iノードキャッシュ上にあるが、 誰からも参照されていない iノード数を示す。