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


375

私は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

ご質問

  1. どのファイルにmkdir実装がありますか?
  2. 上記のような関数定義で、どのファイルが実装されているかをどのように見つけることができますか?メソッドの定義と実装においてカーネルが従うパターンはありますか?

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


2
ちなみに、このチェックアウト:voinici.ceata.org/~tct/resurse/utlk.pdf
トム・ブリト

回答:


386

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

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の機能を、まだシステムコールインターフェースはC-互換性があります。(これは、単一の関数が可変数の引数を取ることができるCのvarargs機能とは異なります。)

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

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

BovetとCesatiによる「Linuxカーネルの理解」のコピーを入手することをお勧めします。


非常に良い答えです。あなたが言及した本についての1つのポイント、「Linuxカーネルの理解」。私はそれを持っていませんが、リリース日(2000)からTOC(オレリーサイトで)は約2.2カーネルと2.4カーネルからの洞察であるように思えます(しかし、私は間違っています)。私の質問は、2.6カーネルの内部をカバーする同等の本がありますか?(または2.2、2.4、および2.6をカバーするより良い)?
DavAlPi

2
@DavAlPi:私が知っている限りでは、Bovet&Cesatiは今でもこのトピックに関する最高の単行本です。最新の資料を追加する必要がある場合Documentationは、作業しているカーネルのソースツリーのサブディレクトリを掘り下げます。
ウォーレンヤング

1
実際、open(2)は可変引数関数です。呼び出す方法は2つしかありません。したがって、マンページではこのように文書化されており、実際のプロトタイプには...varargs関数として含まれています。もちろん、これはlibcレベルで実装されます。3番目のパラメーターが使用されていない場合、カーネルABIに0またはガベージ値を渡すことができます。
Random832

「それはあなたが理解する必要のないものです」。この種の文章がstackexchangeネットワークでどこにも見つからなければ、Worldはより良い場所になるでしょう。
ペトル

84

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

strace -o trace.txt mkdir mynewdir

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


5
+1きちんとしたトリック!以前は使用していませんでした
デビッドオニール

3
さらに良いことに、出力ファイルをtrace.straceにして、VIMで開きます。VIMはそれを強調表示し、読みやすくします。
マルチン

55

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

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

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

OK、sys_mkdiratそれはmkdiratsyscallであることを意味します。したがって、それをクリックすると、の宣言に移動するだけですinclude/linux/syscalls.hが、定義はすぐ上にあります。

の主な仕事mkdiratは、呼び出すことですvfs_mkdir(VFSは汎用ファイルシステム層です)。その上でクリックすると、2つの検索結果が表示されます:の宣言とinclude/linux/fs.h、数行上の定義。の主な仕事はvfs_mkdir、ファイルシステム固有の実装を呼び出すことですdir->i_op->mkdir。どのように見つけるために、これが実装されている、あなたは、個々のファイルシステムの実装に有効にする必要があり、そして何の速いハードとルールはありません-それもカーネルツリー外のモジュールである可能性があります。

¹ LXRは、索引作成プログラムです。LXRへのインターフェイスを提供するWebサイトがいくつかあり、既知のバージョンのわずかに異なるセットとわずかに異なるWebインターフェイスがあります。それらは行き来する傾向があるので、慣れているものが利用できない場合は、「Linux相互参照」をウェブ検索して別のものを見つけます。


これはリソースの1つです。素晴らしい答え。
ステーブルドッグ

linux.noのリンクの「内部サーバーエラー」。
フレドリックガウス

@FredrickGaussしばらくの間、lxr.linux.noはLXRへの最も良いインターフェースでしたが、頻繁にダウンタイムが発生しました。今、私はそれが永久になくなったと思う。最初のリンクを別のLXRインターフェイスに置き換えました。
ジル

21

通常、システムコールはSYSCALL_DEFINEx()マクロでラップされているため、単純なgrepものでは見つかりません。

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

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


17

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

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

mkdir特にシステムコールです。そのシステムコールの周りにGNU libcラッパーがあるかもしれません(実際にはほぼ確実です)。の真のカーネル実装はmkdir、カーネルソースと特にシステムコールを検索することで見つけることができます。

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


8

あなたが見つけた実装はどれもsys / stat.hのプロトタイプと一致しません。たぶん、このヘッダーファイルでincludeステートメントを検索するほうが成功するでしょうか?


1
実装(sys / stat.hで説明)は、ユーザーランドとlibcのビジネスです。カーネル内部のもの(実際に行われる方法)は、カーネル内部ビジネスです。カーネルハッカーが気にするすべての場合、内部関数はxyzzyと呼ばれ、5つのパラメーターを取ることができます。libcの仕事は、ユーザーランドコールを取得し、それを必要なカーネル呪文に変換し、出荷して結果を収集することです。
フォンブランド

6

低レベルのカーネルソースコードを探し出すためのさまざまな手法を説明する、いくつかの本当に素晴らしいブログ投稿があります。


12
ブログやフォーラムへのリンクだけを投稿するのではなく、読者が内容を確認できるように内容を要約し、サイトが消えた場合は何かを残してください。また、最初のリンクはlibcについてであり、これはこの質問のトピック外です。
ジル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.