web-dev-qa-db-ja.com

Linuxカーネルシステムコールの実装を見つけるにはどうすればよいですか?

カーネルソースを調べることで、mkdirなどの関数がどのように機能するかを理解しようとしています。これは、カーネルの内部を理解し、さまざまな機能間を移動する試みです。 mkdirsys/stat.hで定義されています。私はプロトタイプを見つけました:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

次に、この関数が実装されているCファイルを確認する必要があります。ソースディレクトリから、私は試しました

ack "int mkdir"

表示された

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

ただし、sys/stat.hの定義に一致するものはありません。

質問

  1. どのファイルにmkdir実装がありますか?
  2. 上記のような関数定義を使用して、どのファイルに実装があるかをどのように確認できますか?メソッドの定義と実装でカーネルが従うパターンはありますか?

注:私はカーネル 2.6.36-rc1 を使用しています。

376
Navaneeth K N

システムコールは通常の関数呼び出しのようには処理されません。ユーザー空間からカーネル空間への移行を行うには、特別なコードが必要です。基本的に、呼び出しサイトでプログラムに挿入されるインラインアセンブリコードのビットです。システムコールを「キャッチ」するカーネルサイドコードも、少なくとも最初は深く理解する必要のない低レベルのものです。

カーネルソースディレクトリの下の _include/linux/syscalls.h_ には、次のように記載されています。

_asmlinkage long sys_mkdir(const char __user *pathname, int mode);
_

次に_/usr/include/asm*/unistd.h_でこれを見つけます:

_#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)
_

このコードは、mkdir(2)がシステムコール#83であることを示しています。つまり、システムコールは、独自のプログラム内の通常の関数呼び出しやプログラムにリンクされたライブラリ内の関数のように、アドレスではなく番号で呼び出されます。上記のインラインアセンブリグルーコードは、これを使用して、ユーザー空間からカーネル空間に移行し、パラメーターも一緒に取得します。

ここで少し奇妙なことのもう1つの証拠は、システムコールの厳密なパラメーターリストが常に存在するとは限らないことです。たとえば、open(2)は、2つまたは3つのパラメーターを取ることができます。つまり、open(2)オーバーロード であり、CではなくC++の機能ですが、syscallインターフェイスはC互換です。 (これはCの varargs機能 と同じではありません。これにより、単一の関数が可変数の引数を取ることができます。)

最初の質問に答えるために、mkdir()が存在する単一のファイルはありません。 Linuxは多くの異なるファイルシステムをサポートし、それぞれに「mkdir」操作の独自の実装があります。カーネルがそれらすべてを単一のシステムコールの背後に隠すようにする抽象化レイヤーは [〜#〜] vfs [〜#〜] と呼ばれます。したがって、_fs/namei.c_をvfs_mkdir()で掘り始めたいと思うでしょう。低レベルのファイルシステム変更コードの実際の実装は別の場所にあります。たとえば、ext4実装はext4_mkdir()と呼ばれ、 _fs/ext4/namei.c_ で定義されます。

2番目の質問については、はい、これにはすべてパターンがありますが、単一のルールではありません。実際に必要なのは、特定のシステムコールを探す場所を見つけるためにカーネルがどのように機能するかをかなり広く理解することです。すべてのシステムコールがVFSに関係するわけではないため、カーネル側のコールチェーンがすべて_fs/namei.c_で始まるわけではありません。たとえば、mmap(2)_mm/mmap.c_ で始まります。これは、カーネルのメモリ管理( "mm")サブシステムの一部だからです。

BovetとCesatiによる " nderstanding the Linux Kernel "のコピーを入手することをお勧めします。

388
Warren Young

これはおそらくあなたの質問に直接答えることはありませんが、最も単純なシェルコマンドでさえ行われている基本的なシステムコールの実際の動作を理解しようとすると、straceが本当にクールであることがわかりました。例えば.

strace -o trace.txt mkdir mynewdir

コマンドmkdir mynewdirのシステムコールはtrace.txtにダンプされ、表示されます。

86
Banjer

Linuxカーネルソースを読むのに適した場所は Linux相互参照(LXR) ¹です。検索では、フリーテキスト検索の結果に加えて、型指定された一致(関数のプロトタイプ、変数の宣言など)が返されるため、単なるgrepよりも便利です(高速でもあります)。

LXRはプリプロセッサ定義を拡張しません。システムコールの名前は、プリプロセッサによっていたるところに壊されています。ただし、ほとんど(すべて?)のシステムコールは、マクロの SYSCALL_DEFINEx ファミリの1つで定義されています。 mkdirは2つの引数を取るため、SYSCALL_DEFINE2(mkdirを検索すると mkdir syscall

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

さて、sys_mkdiratmkdiratシステムコールであることを意味するので、それをクリックするとinclude/linux/syscalls.hの宣言だけが表示されますが、定義は上記のとおりです。

mkdiratの主な仕事は vfs_mkdir を呼び出すことです(VFSは一般的なファイルシステムレイヤーです)。それをクリックすると、2つの検索結果が表示されます。include/linux/fs.hでの宣言と、上の数行の定義です。 vfs_mkdirの主な役割は、ファイルシステム固有の実装dir->i_op->mkdirを呼び出すことです。 thisの実装方法を見つけるには、個々のファイルシステムの実装に目を向ける必要があり、厳格な規則はありません。カーネル外のモジュールである可能性もあります木。

¹ LXRは索引付けプログラムです。 LXRへのインターフェースを提供するいくつかのWebサイトがあり、既知のバージョンのセットが少し異なり、Webインターフェースが少し異なります。彼らは行き来する傾向があるので、慣れているものが利用できない場合は、「linux cross-reference」をウェブ検索して別のものを見つけてください。

システムコールは通常SYSCALL_DEFINEx()マクロでラップされます。そのため、単純なgrepはそれらを見つけられません。

_fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
_

マクロが展開された後の最終的な関数名は、最終的に_sys_mkdir_になります。 SYSCALL_DEFINEx()マクロは、各syscall定義に必要なトレースコードなどの定型的なものを追加します。

22
stefanha

注:.hファイルはdefine関数ではありません。その.hファイルではdeclaredであり、他の場所で定義(実装)されています。これにより、コンパイラは関数のシグネチャ(プロトタイプ)に関する情報を含めて、引数の型チェックを可能にし、戻り型をコード内の呼び出しコンテキストに一致させることができます。

一般に、Cの.h(ヘッダー)ファイルは、関数の宣言とマクロの定義に使用されます。

特にmkdirはシステムコールです。そのシステムコールの周りにGNU libcラッパーが存在する可能性があります(ほとんどの場合、実際にはそうです)。mkdirの真のカーネル実装は、特にカーネルソースとシステムコールを検索します。

ファイルシステムごとに、ある種のディレクトリ作成コードの実装もあることに注意してください。 VFS(仮想ファイルシステム)レイヤーは、システムコールレイヤーが呼び出すことができる共通のAPIを提供します。すべてのファイルシステムは、VFSレイヤーが呼び出す関数を登録する必要があります。これにより、さまざまなファイルシステムがディレクトリの構造化方法に独自のセマンティクスを実装できます(たとえば、特定のエントリの検索をより効率的にするために、ある種のハッシュスキームを使用して格納されている場合)。 Linuxカーネルソースツリーを検索している場合、これらのファイルシステム固有のディレクトリ作成関数を実行する可能性が高いため、これについて言及します。

17
Jim Dennis

見つかった実装のいずれもsys/stat.hのプロトタイプと一致しません

8
greg0ire

以下は、低レベルのカーネルソースコードを探すためのさまざまな手法を説明する、2つの本当に素晴らしいブログ投稿です。

6
An̲̳̳drew