Linuxは実際のファイルと存在しない(例:デバイス)ファイルをどのように区別しますか?


28

これはかなり低レベルの質問であり、尋ねるのに最適な場所ではないかもしれないことを理解しています。しかし、それは他のどのSEサイトよりも適切であるように思えたので、ここに行きます。

Linuxファイルシステムでは、いくつかのファイルが実際に存在することを知って/usr/bin/bashいます。たとえば:は存在するファイルです。しかし、(私の知る限りそれを理解したように)、いくつかは、実際よりのような存在とされていない仮想ファイルを、例えば:/dev/sda/proc/cpuinfoなど私の質問は(彼らは2つですが、あまりにも密接に別の質問であることを関連します):

  • 読み取りコマンド(またはそのような)が発行されたときに、これらのファイルが本物である(したがって、ディスクから読み取る)かどうかにかかわらず、Linuxカーネルはどのように動作しますか?
  • ファイルが本物ではない場合:例として、read from /dev/randomはランダムデータを返し、read from /dev/nullはを返しEOFます。どのようにこの仮想ファイルからどのデータを読み取るのか(したがって、データが仮想ファイルに書き込まれたとき/場合に何をするのか)-各ファイルに適切な別々の読み取り/書き込みコマンドへのポインタを持つ何らかのマップがありますか?または、仮想ディレクトリ自体についても?したがって、のエントリ/dev/nullは単にを返すことができEOFます。

1
ファイルが作成されると、カーネルはそのタイプを記録します。通常のディスクファイルは、シンボリックリンク、ブロックデバイス、キャラクターデバイス、ディレクトリ、ソケット、FIFOなどとは異なる方法で処理されます。これはカーネルの仕事です。
ジョナサンレフラー

mknodのman pgeを参照してください
Jasen

これは、「ライトがオンになっているかどうかをライトスイッチがどのように知るのか」というようなものです。ライトスイッチは、ライトをオンにするかどうかを決定します。
モニカとの明るさのレース

回答:


25

そのため、ここには基本的に2つの異なるタイプのものがあります。

  1. 通常のファイルシステム。データとメタデータを含むディレクトリ内のファイルを使い慣れた方法で保持します(ソフトリンク、ハードリンクなどを含む)。これらは、常にではありませんが、多くの場合、永続ストレージ用のブロックデバイスによってサポートされます(tmpfsはRAMにのみ存在しますが、それ以外は通常のファイルシステムと同じです)。これらのセマンティクスはおなじみです。読み取り、書き込み、名前の変更など、すべてが期待どおりに機能します。
  2. さまざまな種類の仮想ファイルシステム。/procそして、/sysのようなFUSEカスタムファイルシステムであるため、ここでは一例でありsshfsかはifuse。これらには、はるかに多様性があります。実際には、何らかの意味で「カスタム」であるセマンティクスを持つファイルシステムを単に参照しているからです。したがって、の下のファイルから読み取るとき/proc、通常のファイルシステムのように、以前に何かを書き込んだことによって保存された特定のデータに実際にアクセスすることはありません。基本的にカーネルコールを実行し、オンザフライで生成されたいくつかの情報を要求しています。そして、このコードは、readセマンティクスを実装する機能の一部にすぎないため、好きなことを何でも実行できます。したがって、/procたとえば、シンボリックリンクのふりをしているようなファイルの奇妙な動作があります

キーは、/dev実際には、通常、最初の種類の1つです。現代のディストリビューションでは/devtmpfsのようなものが一般的ですが、古いシステムでは特別な属性を持たないディスク上のプレーンディレクトリであるのが普通でした。重要なのは、配下のファイル/devがデバイスノードであるということです。これは、FIFOやUnixソケットに似たタイプの特殊ファイルです。デバイスノードにはメジャー番号とマイナー番号があり、それらの読み取りまたは書き込みはカーネルドライバーの呼び出しを行っています。FIFOの読み取りまたは書き込みがカーネルを呼び出して出力をパイプにバッファリングするのと同じです。このドライバーは何でもできますが、通常は何らかの方法でハードウェアに触れます。たとえば、ハードディスクにアクセスしたり、スピーカーでサウンドを再生したりします。

元の質問に答えるには:

  1. 「ファイルが存在する」かどうかに関連する2つの質問があります。これらは、デバイスノードファイルが文字通り存在するかどうか、そしてそれを支えるカーネルコードが意味があるかどうかです。前者は通常のファイルシステム上のものと同様に解決されます。最新のシステムはudev、ハードウェアイベントを監視し、それに/dev応じてデバイスノードを自動的に作成および破棄するために、またはそのようなものを使用します。しかし、古いシステム、または軽量のカスタムビルドでは、文字通りすべてのデバイスノードを事前に作成しておくことができます。一方、これらのファイルを読むとき、メジャーおよびマイナーデバイス番号によって決定されるカーネルコードの呼び出しを行っています。これらが妥当でない場合(たとえば、存在しないブロックデバイスを読み取ろうとしている場合)、何らかのI / Oエラーが発生します。

  2. どのデバイスコードに対してどのカーネルコードを呼び出すかを決定する方法は異なります。のような仮想ファイルシステムの場合/proc、独自の関数readwrite関数を実装します。カーネルは、どのマウントポイントにあるかに応じてそのコードを呼び出すだけで、ファイルシステムの実装が残りを処理します。デバイスファイルの場合、メジャーおよびマイナーデバイス番号に基づいてディスパッチされます。


たとえば、古いシステムの電源を切った場合、ファイル/devはまだそこにありますが、システムの起動時にクリアされると思いますか?
ジョー

2
古いシステム(動的なデバイス作成のないシステム)が正常または異常にシャットダウンされた場合、デバイスノードはファイルと同様にディスク上に残ります。その後、次のブートアップが発生した場合、それらもディスク上に残り、通常どおり使用できます。最新のシステムでのみ、デバイスノードの作成と破壊に関して特別なことが発生します。
トム・ハント

したがって、aを使用しない最新のシステムはtmpfs、必要に応じて動的に作成および削除します。例:起動とシャットダウン?
ジョー

3
devtmpfs/dev最新のLinux のファイルシステムはa tmpfsに似ていますが、サポートするにはいくつかの違いがありudevます。(カーネルはudev、ブートの複雑さを軽減するために、自動でノードを作成します。これらのすべての場合、デバイスノードはRAMにのみ存在し、ハードウェアが必要とするため、動的に作成および破棄されます。おそらくあなたはudev通常のオンディスク/devでも使用できますが、私はこれが行われたことを一度も見たことがなく、正当な理由はないようです。
トム・ハント

17

以下/dev/sda1は、ほぼ最新のArch Linuxサーバー上のファイルリストです。

% ls -li /dev/sda1
1294 brw-rw---- 1 root disk 8, 1 Nov  9 13:26 /dev/sda1

したがって、/dev/for のディレクトリエントリにsdaは、iノード番号1294があります。これは、ディスク上の実際のファイルです。

ファイルサイズが通常表示される場所を確認します。代わりに「8、1」が表示されます。これはメジャーおよびマイナーデバイス番号です。ファイル許可の「b」にも注意してください。

ファイルに/usr/include/ext2fs/ext2_fs.hは、この(フラグメント)C構造体が含まれています。

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
    __u16   i_mode;     /* File mode */

この構造は、ファイルのiノードのディスク上の構造を示しています。その構造体には興味深いものがたくさんあります。じっくり見てください。

i_mode要素struct ext2_inodeは16ビットであり、ユーザー/グループ/その他、読み取り/書き込み/実行の許可には9のみ、setuid、setgid、およびstickyには3のみを使用します。「プレーンファイル」、「リンク」、「ディレクトリ」、「名前付きパイプ」、「Unixファミリソケット」、「ブロックデバイス」などのタイプを区別するための4ビットがあります。

Linuxカーネルは、通常のディレクトリルックアップアルゴリズムに従って、i_mode要素内の権限とフラグに基づいて決定を下すことができます。'b'の場合、デバイスファイルをブロックし、メジャーデバイス番号とマイナーデバイス番号を検索します。従来は、メジャーデバイス番号を使用して、ディスクを処理するカーネル関数(デバイスドライバー)へのポインターを検索します。通常、マイナーデバイス番号は、SCSIバスデバイス番号、EIDEデバイス番号、またはそのようなものとして使用されます。

のようなファイルの処理方法に関するその他の決定/proc/cpuinfoは、ファイルシステムのタイプに基づいて行われます。あなたがする場合:

% mount | grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

/procファイルシステムタイプが「proc」であることがわかります。内のファイルからの読み込み/procだけでReiserFSのか、DOSのファイルシステム上のファイルを開くと、ファイルシステムのタイプに基づいて異なる何かをする原因カーネルは、カーネルは、ファイルを見つけるためにさまざまな機能を使用するようになり、そしてのデータを見つけるだろうファイル。


「ディスク上の実際のファイル」のみにiノード番号が表示されていると確信していますか?私が取得4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstat明確に、「実際のファイル」されていません。
ガントベルト

7

結局のところ、それらはすべてUnix用のファイルです。これが抽象化の美しさです。

カーネルがファイルを処理する方法は、今では異なる話です。

/ procおよび最近の/ devおよび/ run(別名/ var / run)は、RAM内の仮想ファイルシステムです。/ procは、カーネル変数および構造へのインターフェイス/ウィンドウです。

The Linux Kernel http://tldp.org/LDP/tlk/tlk.htmlおよびLinux Device Drivers、Third Edition https://lwn.net/Kernel/LDD3/を読むことをお勧めします

また、FreeBSDオペレーティングシステムの設計と実装も楽しみました。http://www.amazon.com/Design-Implementation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

質問に関連する関連ページをご覧ください。

http://www.tldp.org/LDP/tlk/dd/drivers.html


おかげで、あなたがコメントした後、最初の質問を少し変更しました。
ジョー

最後のコメントを読んでください。
ルイFリベイロ

5

@RuiFRibeiroと@BruceEdigerの回答に加えて、あなたが行う区別は、カーネルが行う区別とは異なります。実際には、通常のファイル、ディレクトリ、シンボリックリンク、デバイス、ソケットなど、さまざまな種類のファイルがあります(完全にリストを作成しようとは思わないので、いくつかはいつも忘れています)。ファイルのタイプに関する情報を取得するにはls、行の最初の文字を使用します。例えば:

$ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 17 nov.  08:29 /dev/sda

最初の「b」は、このファイルがブロックデバイスであることを示しています。ダッシュは通常のファイル、 'l'はシンボリックリンクなどを意味します。この情報はファイルのメタデータに保存され、statたとえばシステムコールを介してアクセスできるため、カーネルはたとえばファイルとシンボリックリンクを別々に読み取ることができます。

次に、「実際のファイル」のようなもの/bin/bashと「仮想ファイル」のようなものを区別します/proc/cpuinfoが、ls両方を通常のファイルとして報告するため、違いは別の種類になります。

ls -la /proc/cpuinfo /bin/bash
-rwxr-xr-x 1 root root  829792 24 août  10:58 /bin/bash
-r--r--r-- 1 root wheel      0 20 nov.  16:50 /proc/cpuinfo

起こるのは、それらが異なるファイルシステムに属するということです。/proc疑似ファイルシステムのマウントポイントであるのprocfsに対し/bin/bash、通常のディスクファイルシステム上にあります。Linuxがファイルを開くと(ファイルシステムに応じて異なる方法で)、fileこのファイルを使用する方法を説明するいくつかの関数ポインターの構造などの属性を含むデータ構造が読み込まれます。したがって、ファイルの種類ごとに異なる動作を実装できます。

たとえば、これらは次によってアドバタイズされる操作/proc/meminfoです。

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

static const struct file_operations meminfo_proc_fops = {
    .open       = meminfo_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

の定義をmeminfo_proc_open見ると、この関数meminfo_proc_showは、メモリ使用量に関するデータを収集することを目的とする関数によって返される情報をメモリ内のバッファに取り込むことがわかります。その後、この情報は正常に読み取ることができます。ファイルを開くたびに、関数meminfo_proc_openが呼び出され、メモリに関する情報が更新されます。


3

ファイルシステム内のすべてのファイルは、ファイルI / Oを許可するという意味で「実際の」ファイルです。ファイルを開くと、カーネルはファイル記述子を作成します。これは、ファイルのように動作するオブジェクト(オブジェクト指向プログラミングの意味で)です。ファイルを読み取る場合、ファイル記述子はその読み取りメソッドを実行し、ファイルからのデータをファイルシステム(sysfs、ext4、nfsなど)に要求します。ファイルシステムは、ユーザースペースへの統一されたインターフェースを提供し、読み取りと書き込みを処理するために何をすべきかを知っています。ファイルシステムは、他のレイヤーにリクエストを処理するように順番に要求します。ext4ファイルシステムなどの通常のファイルの場合、これにはファイルシステムのデータ構造(ディスクの読み取りが含まれる場合があります)のルックアップが含まれ、最終的にディスク(またはキャッシュ)からの読み取りが読み取りバッファーにデータをコピーします。たとえば、sysfsのファイルの場合、通常、バッファに何かをsprintf()します。ブロック開発ノードの場合、ディスクドライバーにいくつかのブロックを読み取ってバッファーにコピーするように要求します(メジャー番号とマイナー番号は、どのドライバーに要求するかをファイルシステムに通知します)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.