はじめに
こんにちは。Linuxカーネル研究のために無職になった人です。
今、以下のようなLinuxカーネルを解説するサイトを作っているのですが、ちょっと説明がわかりづらい気もしたので、追加説明という意味で記事を書きました。
今後は linux.tokyo に登録するのみならず、1つ1つの linux.tokyo で登録した内容を記事の形で説明していこうと思っています。
そこで、今回は「Open」システムコールから始めようと思います。ちょっと最初の方にやった「Write」とか「Exec」は内容的に未熟である可能性があり、心配なので...
ちょっと記事にlinux.tokyoへのリンクが多くなってしまっているのですが、ご容赦ください。
また、何か間違いがありましたらお気軽にコメントをくださいmm
Openシステムコールの内容
1. do_sys_open
エントリーポイントになる関数。
do_sys_open
get_unused_fd_flags
alloc_fd
expand_file ⭐︎1
__set_open_fd ⭐︎2
do_filp_open
init_file ⭐︎3
path_init ⭐︎4
link_path_walk
lookup_fast ⭐︎5
lookup_slow ⭐︎6
do_dentry_open ⭐︎7
f->f_op->open ⭐︎8
set_nameidata
__set_nameidata ⭐︎9
fd_install
files_fdtables ⭐︎10
◾️大枠の流れ
大枠では以下の流れになります。
一:get_unused_fd_flags
未使用の FD 番号を確保。リンク
二:do_filp_open
struct fileの作成。リンク
三:fd_install
確保済み fd と生成された struct file をプロセスのファイルディスクリプタテーブルに結び付け、のちに参照可能にする。リンク
↓ fd確保
1:get_unused_fd_flags > alloc_fd > expand_file
一でfdが足りない場合に、fdtableを動的に拡張し、より多く確保できるようにする。リンク
2:get_unused_fd_flags > alloc_fd > __set_open_fd
一で最終的に「このFDを占有する」と言う状態にする。リンク
↓ struct file確保
3:do_filp_open > init_file
struct fileを初期化する。リンク
↓ パス確保
4:do_filp_open > path_init
起点パス (cwd か root 等) を決定してパス走査の準備を整える。リンク
5:do_filp_open > link_path_walk > lookup_fast
高速でパス解決を最短経路で完了させる試みを行う。リンク
6:do_filp_open > link_path_walk > lookup_slow
lookup_fastでキャッシュ未ヒット時に、パス解決を再度行う。リンク
↓ block層確保
7:do_filp_open > do_dentry_open
struct fileへの情報追加と、block層の確保の入り口。リンク
8:do_filp_open > do_dentry_open > f->f_op->open
ファイルシステム固有のopenハンドラを呼び出し、デバイスやファイルシステム特有の初期化処理を実行する。ext4_file_open等の実装が呼ばれる。リンク
↓ nameidataの確保
9:do_filp_open > set_nameidata > __set_nameidata
nameidata構造体にデータを入れ、名前解決のコンテキストを初期化する。リンク
↓ 最終的な紐付け
10:fd_install > fd_install
確保済み fd と生成された struct file をプロセスのファイルディスクリプタテーブルに結び付け、のちに参照可能にする。リンク
2. ext4_file_open
上記のdo_sys_openの8のf->f_op->openの中身の実装を説明します。
ext4_file_open
ext4_inode_attach_jinode
jbd2_alloc_inode
jbd2_journal_init_jbd_inode
◾️実装の流れ
以下の流れになります。
1:jbd2_alloc_inode
ジャーナリング層(JBD2)用のjbd2_inode構造体をメモリ確保し取得する。リンク
2:jbd2_journal_init_jbd_inode
確保したjbd2_inodeとVFS inodeを結び付け、ジャーナルに対して当該inodeを登録する初期化処理。リンク
3. ext4_lookup
上記のdo_sys_openの lookup_slow で lookupをしているが、そのlookupがext4などのファイルシステム依存なので、ここでそのlookupを説明する。
ext4_lookup
ext4_find_inline_entry
submit_bio ⭐︎1
ext4_match ⭐︎2
ext4_dx_find_entry
ext4_map_blocks ⭐︎3
find_get_block_common ⭐︎4
ext4_match ⭐︎5
◾️大枠の流れ
大枠、以下の流れになります。
一:ext4_find_inline_entry
小規模ディレクトリの検索で使われる検索方法。リンク
二:ext4_dx_find_entry
ハッシュインデックス(dx)を有効にしているときに、B-tree 風のインデックスを用いてエントリを高速検索する検索方法。リンク
↓ inline検索
1:ext4_find_inline_entry > submit_bio
準備した BIO をブロック層へ送出し、ディスク読み取りを開始する。リンク
2:ext4_find_inline_entry > ext4_match
ディレクトリエントリの名前が一致するかの確認。リンク
↓ dx検索
3:ext4_dx_find_entry > ext4_map_blocks
論理ブロック番号を物理ブロックに変換し、必要に応じて新規割当も行う。リンク
4:ext4_dx_find_entry > find_get_block_common
指定ブロック番号に対応するbuffer_headをページキャッシュから検索し、保持参照を返す。リンク
5:ext4_dx_find_entry > ext4_match
ディレクトリエントリの名前が一致するかの確認。リンク
結び
ここまで「Open」システムコールを説明しました。
大まかな流れとしては、do_sys_openから「fd確保→struct file確保(ext4_lookup)→パス確保→ブロック層確保(ext4_file_open)→nameidata確保→最終的な紐付け」の流れでした。
次回は長くなりますが「Read」を解説していきます。