カーネルソースを調べることで、mkdir
などの関数がどのように機能するかを理解しようとしています。これは、カーネルの内部を理解し、さまざまな機能間を移動する試みです。 mkdir
はsys/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
の定義に一致するものはありません。
質問
mkdir
実装がありますか?注:私はカーネル 2.6.36-rc1 を使用しています。
システムコールは通常の関数呼び出しのようには処理されません。ユーザー空間からカーネル空間への移行を行うには、特別なコードが必要です。基本的に、呼び出しサイトでプログラムに挿入されるインラインアセンブリコードのビットです。システムコールを「キャッチ」するカーネルサイドコードも、少なくとも最初は深く理解する必要のない低レベルのものです。
カーネルソースディレクトリの下の _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 "のコピーを入手することをお勧めします。
これはおそらくあなたの質問に直接答えることはありませんが、最も単純なシェルコマンドでさえ行われている基本的なシステムコールの実際の動作を理解しようとすると、strace
が本当にクールであることがわかりました。例えば.
strace -o trace.txt mkdir mynewdir
コマンドmkdir mynewdir
のシステムコールはtrace.txtにダンプされ、表示されます。
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_mkdirat
はmkdirat
システムコールであることを意味するので、それをクリックすると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定義に必要なトレースコードなどの定型的なものを追加します。
注:.hファイルはdefine関数ではありません。その.hファイルではdeclaredであり、他の場所で定義(実装)されています。これにより、コンパイラは関数のシグネチャ(プロトタイプ)に関する情報を含めて、引数の型チェックを可能にし、戻り型をコード内の呼び出しコンテキストに一致させることができます。
一般に、Cの.h(ヘッダー)ファイルは、関数の宣言とマクロの定義に使用されます。
特にmkdir
はシステムコールです。そのシステムコールの周りにGNU libcラッパーが存在する可能性があります(ほとんどの場合、実際にはそうです)。mkdir
の真のカーネル実装は、特にカーネルソースとシステムコールを検索します。
ファイルシステムごとに、ある種のディレクトリ作成コードの実装もあることに注意してください。 VFS(仮想ファイルシステム)レイヤーは、システムコールレイヤーが呼び出すことができる共通のAPIを提供します。すべてのファイルシステムは、VFSレイヤーが呼び出す関数を登録する必要があります。これにより、さまざまなファイルシステムがディレクトリの構造化方法に独自のセマンティクスを実装できます(たとえば、特定のエントリの検索をより効率的にするために、ある種のハッシュスキームを使用して格納されている場合)。 Linuxカーネルソースツリーを検索している場合、これらのファイルシステム固有のディレクトリ作成関数を実行する可能性が高いため、これについて言及します。
見つかった実装のいずれもsys/stat.hのプロトタイプと一致しません
以下は、低レベルのカーネルソースコードを探すためのさまざまな手法を説明する、2つの本当に素晴らしいブログ投稿です。