\r\n\r\n
Linuxのファイルシステムはinodeに依存している。これらのファイルシステム内部の重要な部分は、しばしば誤解されることがある。その実態と役割について見ていきましょう。
定義上、ファイルシステムはファイルを格納する必要があり、またディレクトリも格納する。ファイルはディレクトリに格納され、そのディレクトリはサブディレクトリを持つことができます。ファイルシステム内のすべてのファイルの場所、名前、所属するアカウント、持っている権限などをどこかに記録しておく必要があります。この情報は、他のデータを説明するデータであるため、メタデータと呼ばれる。
LinuxExt4ファイルシステムでは、inode構造とディレクトリ構造を合わせて、各ファイルとディレクトリのすべてのメタデータを格納するための基本フレームワークを提供します。カーネル、ユーザーアプリケーション、ls、stat、dfなどのLinuxユーティリティなど、メタデータを必要とするすべての人が利用できるようにするのです。
このような構造のペアは存在しますが、ファイルシステムにはそれ以上のものが要求されます。各ビルの構造は数千種類にも及びます。各ファイルとディレクトリにはinodeが必要で、各ファイルはディレクトリの中にあるため、各ファイルにもディレクトリ構造が必要です。ディレクトリ構造は、ディレクトリエントリ、または "デントリ" とも呼ばれます。
各inodeはinode番号を持ち、これはファイルシステム内で一意である。同じinode番号が複数のファイルシステム上に現れることがあります。しかし、ファイルシステムIDとinode番号の組み合わせは、Linuxシステム上にいくつのファイルシステムがインストールされていても、一意な識別子を形成します。
Linuxでは、ハードディスクやパーティションをマウントする必要がないことを覚えておいてください。パーティションにファイルシステムをマウントすることができるので、気づかないうちに複数のファイルシステムを持つことが簡単にできます。複数のハードディスクや1つのドライブにパーティションがある場合、複数のファイルシステムが存在することになります。例えば、すべてext4と同じタイプであっても、異なるファイルシステムであることに変わりはありません。
すべてのインデックスノードは、1つのテーブルに配置されます。inode番号を使えば、ファイルシステムはinodeがあるinodeテーブルのオフセットを簡単に計算することができる。inodeの "i "がindexの意味であることはおわかりいただけたかと思います。
inode番号を格納する変数は、ソースコード上では32ビットの符号なし長整数として宣言されています。つまり、inode番号は最大値2^32の整数値であり、計算すると4294967295となり、40億inodeを優に超える。
これが理論上の最大値です。実際には、ext4ファイルシステムのinode数は、ファイルシステム容量16kbにつき1inodeというデフォルトの割合でファイルシステムが作成されるときに決定されます。ディレクトリ構造は、ファイルシステムが使用されると、ファイルシステム内にファイルやディレクトリが作成され、動的に作成されます。
dfコマンドの-i(inodes)オプションは、inodeの数で出力を表示するように指示します。
1台目のドライブの1番目のパーティションのファイルシステムを見るので、次のように入力します。
df -i /dev/sda1私たちにアウトプットしてください。
このファイルシステムでは10%のinodeを使用している。ファイルはハードディスク上のディスクブロックとして格納される。各inodeは、それが表すファイルの内容を格納するディスクブロックを指している。何百万もの小さなファイルがある場合、ハードディスクの容量がなくなる前にインデックスノードを使い果たす可能性があります。しかし、これは非常に難しい問題です。
かつて、一部のメールサーバーでは、メールを個別のファイルとして保存することでこの問題を解決していた(すぐに小さなファイルの大きなコレクションになってしまう)。これは、これらのアプリケーションのバックエンドをデータベースに変更することで解決しました。通常のホームシステムでは、inodeが不足することはありません。これは、ext4ファイルシステムでは、ファイルシステムを再インストールしないとinodeを追加することができないためです。
ファイルシステム上のディスクブロックのサイズを見るには、 blockdev コマンドと --getbsz (get block size) オプションを使用します。
sudo blockdev --getbsz /dev/sdaブロックサイズは4096バイトです。
B(ブロックサイズ)オプションでブロックサイズを4096バイトに指定し、通常のディスク使用量を確認してみましょう:。
df -B 4096 /dev/sda1このように出力されます。
この例では、ファイルの保存(およびinodeとディレクトリ構造の保存)がすでにこのファイルシステムの領域の28%を占め、inodeの10%を犠牲にしているので、良い状態にあります。
ファイルのinode番号を表示するには、lsオプションと-i(inode)オプションを使用します。
ls -i geek.txtこのファイルのinode番号は1441801なので、このinodeはこのファイルのメタデータを保持し、従来はファイルがあるハードディスク上のディスクブロックへのポインタであった。ファイルが断片化されているか、非常に大きいか、またはその両方である場合、inodeが指すブロックのいくつかは、他のディスクブロックへのさらなるポインタを含んでいる可能性があります。他のディスクブロックの中には、別のディスクブロックのセットへのポインタが含まれている場合もある。これは、inodeのサイズが固定で、ディスクブロックへのポインタを限られた数しか保持できないという問題を克服するものである。
この方法は、ファイルの保存に使用されるデータブロックの連続した各セットの開始ブロックと終了ブロックを記録する「拡張ブロック」を使用する新しい方式に取って代わられた。ファイルが分割されていない場合は、最初のブロックとファイルの長さのみを格納する必要がある。ファイルが分割されている場合、ファイルの各パートの最初と最後のブロックを格納する必要がある。この方法は(当然)より効率的です。
ファイルシステムがディスクブロックポインターを使用しているか、拡張データブロックを使用しているかを確認するには、inodeの内部を見ることができます。そのために、debugfsコマンドに-R(request)オプションを付けて、対象のファイルのinodeを渡します。このため、debugfsはその内部の「stat」コマンドを使ってinodeの内容を表示する必要があります。inode 番号はファイルシステム内で一意であるため、debugfs に inode がどのファイルシステム上にあるかを伝える必要があります。
このコマンドの例は、次のようなものです。
sudo debugfs -R "stat <1441801>" /dev/sda1debugfsコマンドは、以下のようにinodeから情報を抽出し、より短い時間で我々に提示する。
を表示しています。
これでファイルに関する多くの情報を得ることができましたが、お気づきかもしれませんが、ファイル名は得られません。そこで登場するのが、ディレクトリ構造です。Linuxでは、ファイルと同じように、ディレクトリにもinodeがあります。ディレクトリinodeは、ファイルデータを含むディスクブロックを指すのではなく、ディレクトリ構造を含むディスクブロックを指します。
ディレクトリ構造は、inodeと比較して、ファイルに関する限られた情報しか持っていません。それは、ファイルのinode番号、名前、名前の長さを保持しているだけです。
inodeとディレクトリ構造には、あなた(またはアプリケーション)がファイルやディレクトリについて知っておく必要があるすべての情報が含まれています。ディレクトリ構造はディレクトリディスクブロックになっているので、ファイルがあるディレクトリはわかっている。ディレクトリ構造から、ファイル名とinode番号がわかる。inodeは、タイムスタンプ、パーミッション、ファイルシステムのどこにファイルデータがあるかなど、ファイルに関する他のすべての情報を教えてくれる。
ファイルのinode番号を見るのと同じように、ディレクトリのinode番号も簡単に見ることができます。
次の例では、lsに-l(ロングフォーマット)、-i(inode)、-d(ディレクトリ)オプションを付けて使用し、作業ディレクトリを調べます。
ls -lid work/d(ディレクトリ)オプションを使用したため、lsはその内容ではなく、ディレクトリそのものを報告します。このディレクトリのinodeは1443016です。
この操作をホームディレクトリに対して繰り返すには、次のように入力します。
ls -lid ~ホームディレクトリのinodeは1447510で、作業ディレクトリはホームディレクトリの中にあります。では、作業ディレクトリの中身を見てみましょう。ここでは、-d(ディレクトリ)オプションの代わりに、-a(すべて)オプションを使用することにします。これにより、通常は隠されているディレクトリエントリが表示されます。
以下のように入力します。
ls -lia work/a (all)オプションを使っているため、シングルドット(.)が表示されますとダブルドット(.)のエントリーをご覧ください。これらのエントリは、ディレクトリ自体 (シングルドット) とその親ディレクトリ (ダブルドット) を表します。
シングルドットのエントリーのinode番号を見ると、1443016であることがわかります。これは、作業ディレクトリのinode番号を求めたときに得られたものと同じinode番号です。また、ダブルドットエントリーのinode番号は、ホームディレクトリのinode番号と同じになります。
だから、このCDを使うことができるのです。コマンドで、ディレクトリツリーを1つ上に移動します。同様に、アプリケーションやスクリプトの名前の前に.NETを付ける場合も、./ は、アプリケーションやスクリプトをどこから開始するかをシェルに知らせます。
ファイルはハードディスクに保存されるデータで、ディレクトリ構造にはファイル名とそのinode番号、inodeにはファイルのすべてのメタデータが含まれる。
シンボリックリンクは、ファイルのように見えるが、実際には既存のファイルやディレクトリへのショートカットであるファイルシステムのエントリです。この3つの要素を用いて、どのように管理され、どのように実現できるかを見ていきましょう。
以下のように、スクリプト用とアプリケーション用の2つのファイルを含むディレクトリがあるとします。
スクリプトファイルへのソフトリンクは、lnコマンドと-s(symbol)オプションを使って、以下のように作成することができます。
ls -s my_script geek.shmy_script.sh call geekへのリンクを作成しました。次のようにタイプして、lsを使って2つのスクリプトファイルを表示することができます。
ls-li*.sh ファイル
エントリーギクを青色で表示しています。許可マークの最初の文字は「l」で、my_script.shへのリンク->を示しています。これらはすべて、ギークがリンクであることを表しています。
予想通り、2つのスクリプトファイルは異なるinode番号を持っています。しかし、もっと驚くべきことに、ソフトリンクであるgeekは、元のスクリプトファイルと同じユーザー権限を持っていないのです。実際、パーミッションオタクは、全ユーザーのフルパーミッションを持っています。
ディレクトリ構造geekには、リンクの名前とそのinodeが含まれる。リンクを使おうとすると、通常のファイルと同じようにそのinodeが参照されます。リンクのinodeはディスクブロックを指しますが、ディスクブロックにはファイルの内容データは含まれず、元のファイルの名前が含まれます。ファイルシステムは、元のファイルにリダイレクトします。
元のファイルを削除して、次のように入力してオトクに見ることにします。
rm my_script.sh cat geek.shシンボリックリンクが壊れ、リダイレクトに失敗しました。
ここで、アプリケーションファイルへのハードリンクを作成するために、次のように入力します。
ln special-app geek-app両方のファイルのinodeを表示するには、次のように入力します。
ls -liどちらも通常のファイルと同じように見えます。lsリストには、リンクされたギークドであることを示唆するギークアプリの情報はない。また、オトナのアプリは元のファイルと同じユーザー権限を持っています。しかし、驚くべきことに、両方のアプリケーションは同じinode番号:1441797を持っています。
geekアプリのディレクトリエントリには、"geek app "という名前とinode番号が含まれています。実際には、任意の数のエントリが同じinodeを指すことができます。
以下のように入力し、statプログラムを使用して対象ファイルを表示することにします。
stat special-appinodeに格納されているこのファイルには、2つのハードリンクがあることがわかる。
次の例では、元の文書を削除し、秘密の安全なパスワードを持つリンクを使用することを試みます。
rm special-app ./geek-app correcthorsebatterystaple意外なことに、このアプリケーションは期待通りに動作するのですが、どのように?ファイルを削除すると、そのinodeは再利用できるようになるため、うまくいくのです。ディレクトリ構造にはinode番号0が付けられ、そのディスクブロックはそのスペースに格納されている別のファイルに利用できるようになる。
ただし、inodeへのハードリンク数が1より大きい場合は、ハードリンク数を1減らし、ファイルが削除されたディレクトリ構造のinode数を0にする。ハードディスク上のファイルの内容やinodeは、既存のハードリンクで利用可能なままです。
以下のように入力し、geekアプリで再度statを使用することになります。
stat geek-appこれらの詳細は、前回のstatコマンド(1441797)と同じinodeのもので、リンク数が1つ減っています。
このinodeにはハードリンクが1つしかないため、geekアプリケーションを削除すると、実際にファイルが削除されます。ファイルシステムはinodeを解放し、ディレクトリ構造をinodeゼロでマークする。新しいファイルは、ハードディスク上のデータストアを上書きすることができます。
関連:Linuxでのstatコマンドの使い方
ファイルを読み込むには、ファイルシステムは以下の操作をすべて行わなければならない。
データが不連続な場合は、もう少しジャンプする必要があります。
多くのファイルを含むフォーマットされた長いリストを実行するために、lsがしなければならない仕事を想像してみてください。lsの場合、出力を生成するために必要な情報を得るために、多くの行き来があります。
もちろん、ファイルシステムの高速なアクセスは、Linux が可能な限りプリエンプティブなファイルキャッシングを行う理由でもあります。これは非常に便利ですが、他のファイルシステムと同様、オーバーヘッドが明らかになることがあります。
その理由がわかりましたね。