1. 序章

多くの場合、ファイルはコンテンツを含むオブジェクトと見なされます。 しかし、私たちが日常的に扱っているのはリンクだけです。 その下では、ファイルのオブジェクトは実際にはinodeです。

このチュートリアルでは、Linux iノードについて説明します。これらのiノードとは何か、およびそれらを使用する理由と時期について説明します。 まず、ストレージの概念から始めます。 その後、ファイルシステムがストレージデバイスにどのように適用されるかについて説明し、それらの大まかな内部動作を確認します。 次に、iノードがスポットライトを当てて包括的な議論を行います。 最後に、iノードに基づいていくつかのファイルシステムオブジェクトを調べ、いくつかの特別な考慮事項に注意します。

このチュートリアルのコードは、GNU Bash5.1.4を使用したDebian11(Bullseye)でテストしました。 これはPOSIXに準拠しており、そのような環境で機能するはずです。

2. 保管所

ほとんどのマシンは、少なくともメインメモリとセカンダリメモリで動作します。 ほとんどの場合、メインメモリをランダムアクセスメモリ(RAM)と呼びますが、セカンダリメモリまたはストレージは、ハードディスク、ソリッドステートドライブ、および同様のデバイスで構成されます。

それらの種類に関係なく、ストレージデバイスには通常コントローラーがあります。 それぞれのメモリモジュールのインターフェイスをマシンに公開する役割を果たします。 コントローラは、デバイスを同じサイズのブロックとして表示します。

セカンダリメモリのセクターまたは最小ブロックは、最も一般的には512バイトの大きさであることに注意してください。 これは後で重要になります。

ストレージデバイスをより有効に活用するために、オペレーティングシステム(OS)には、コントローラーと通信するためのドライバーがあります。 ただし、ドライバーは依然として非常に生のメモリ構造を示します。 その構造は、別の抽象化を介して使用するためにさらに洗練されています。

3. ファイルシステム

ドライバーはオペレーティングシステムがストレージを認識および制御する方法ですが、ファイルシステムはそれらがそれを注文する方法です。 そのために、ファイルシステムは通常、書籍にある古いメカニズムであるインデックスを使用します。

3.1. メタデータ編成

本のセクションが、ページ番号やタイトルなどの重要な属性とともにどのようにリストされているかを検討してください。 この情報はすべてインデックス内にあります。 一方、索引自体は一方の端がきちんと詰め込まれていて、本のほんの一部しか取りませんが、それでも高速で簡単な閲覧が可能です。

すべてのページが手元になくても、インデックスを使用すると、次のような感覚を得ることができます。

  • 本の長さ
  • どのセクションが短く、どのセクションが長いか
  • セクションの順序
  • どのセクションが他のどのセクションのサブセクションであるか
  • セクションの基本的な特徴(タイトルなど)

ここで、本のセクションの一部が空であると想像してください。 結果として得られる構造は、通常、ファイルシステムの最も基本的な考え方です。

特に、インデックスはファイルシステムに関連付けられたメタデータを表します。 解放された、またはファイルに割り当てられたセクションは、ブロックとも呼ばれ、メモリの物理的な部分を表します。 ファイルシステムインデックスは、本のページのように、すばやく簡単に閲覧できるようにそれらを整理します。

3.2. 例

実際、ほとんどのファイルシステムには、ブロックを指す何らかのサポート組織があります。

  • FAT (ファイルアロケーションテーブル)にはファイルアロケーションテーブルがあります(そのため、 FAT という名前が付けられています)
  • exFAT (拡張ファイルアロケーションテーブル)は基本的にファイルアロケーションテーブルを拡張します
  • NTFS (新技術ファイルシステム)は、はるかに高度なマスターファイルテーブルを使用します

Linuxは多くのファイルシステムをサポートしていますが、ネイティブはそのうちのいくつかだけです。 注目すべき例の1つは、 ext (拡張ファイルシステム)ファミリーシステム(ext2、ext3、およびext4)です。 もう1つの良い例は、 XFS (Xファイルシステム)です。 これからは、ネイティブLinuxファイルシステムが広く使用され、メタデータの鍵となる概念を共有しているため、ネイティブLinuxファイルシステムがどのように機能するかについてのみ説明します。

この概念を調べてみましょう。

4. iノード

iノードという用語は、インデックスノードに由来します。 ファイルシステム組織が本の索引のようなものであることについてはすでに説明したので、iノードがこのアイデアにどのようにうまく適合するかを見ることができます。

特に、iノードを本のインデックスエントリの行番号と同等にすることができますこのように、iノードを使用するとメインインデックスにインデックスを付けることができます。 オペレーティングシステムは、各iノードに一意の整数を割り当てるため、すでに説明した内部ファイルシステム構造のキーとして使用できます。

iノードが特定のファイルに対して指す情報のほとんどを取得するには、 stat コマンドを使用できます。このコマンドは、statシステムコールを内部的に実行します。

$ stat file.ext
File: file.ext
Size: 166 Blocks: 8 IO Block: 4096 regular file
Device: 810h/2064d Inode: 666 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 1000/ x) Gid: ( 1000/ x)
Access: 2021-11-11 10:00:00.101020201 +0200
Modify: 2021-11-11 10:00:00.101020201 +0200
Change: 2021-11-11 10:00:00.101020201 +0200
Birth: 2021-11-11 10:00:00.101020201 +0200

この情報を上から下、左から右の構成要素に分解してみましょう。 出力はファイルの名前とサイズで始まります。 後者は、指定されたサイズ(8 * 512 = 4096バイト)のバイト(166)およびブロック(8)です。 すでに述べたように、物理ブロックはほとんどの場合512バイトですが、特定のファイルシステムでデバイスまたはパーティションをフォーマットするときにIOブロックサイズを指定できます。 リンクは直接ではありませんが、存在します。 2行目の終わりに、通常のファイルstatを使用したことがわかります。

次に、16進数(810)と10進数(2064)のデバイスIDがあります。 もちろん、iノード番号(666)が表示されます。 4行目の最後は、このiノードへのリンクの数です。 リンクについては、次のセクションで説明します。

所有権とアクセス権専用の行全体があります。 最後に、アクセス、変更、変更、および作成(生年月日)の日付専用の4つの行が表示されます。 ファイルを変更するということは、そのメタデータを変更することを意味することに注意してください。

実際、多くのファイルシステムオブジェクトには独自のiノードがあります。 実際、それらの特定の性質に関係なく、それらはすべてファイルです。

5. ファイルシステムオブジェクト

これまで、ファイルシステムのメタデータについて話してきました。 ただし、すべてのファイルシステムは、保存する実際のデータを整理するために存在します。 私たちにとって、メタデータはほとんど隠されています。 表示されるのはファイルシステムオブジェクトです。

ほとんどのファイルシステムにおけるそのような主なオブジェクトはファイルです。 ネイティブLinuxファイルシステムでは、ファイルという用語は、iノードが関連付けられているオブジェクトを意味します。 それらは多くの異なるタイプである可能性があります:

一般的なものを調べてみましょう。

5.1. 通常のファイル

通常のファイルは、通常ファイルという単語に関連付けられているデータのコレクションです。 iノードのメタデータとは別に、通常のファイルにはシステム以外のコンテンツが含まれており、エディターやその他のツールを介して読み書きします。

重要なのは、 debugfs (ファイルシステムデバッガー)を介してファイルの内容がどのように拡散されているかを確認できることです。

$ debugfs /dev/sda
debugfs 1.46.2 (20-Nov-2021)
debugfs: inode_dump -b /file.ext
0000 0af3 0100 0400 0000 0000 0000 0000 0000 ................
0020 0100 0000 0034 1100 0000 0000 0000 0000 .....4..........
0040 0000 0000 0000 0000 0000 0000 0000 0000 ................
*

まず、ファイルシステムブロックデバイスを引数としてdebugfsを開始します。 その後、inode_dumpコマンドと-bフラグを使用して、ファイルがどのブロックで構成されているかを識別子で示します。

通常、ほとんどのファイルはディレクトリ内に保存されます。

5.2. ディレクトリ

ディレクトリはファイルシステム内のコンテナです–他のディレクトリを含むほとんどのオブジェクトを保存できます。 Linuxディレクトリは、iノード番号マッピングへのファイル名のリストです。 ユーザーはこの構造をツリーの形で見ることができます。

実際、 tree コマンドを使用して、これを確認できます。

$ tree -L 2 -d /etc/systemd/
/etc/systemd/
|-- network
|-- system
| |-- default.target.wants
| |-- getty.target.wants
| |-- multi-user.target.wants
| |-- network-online.target.wants
| |-- remote-fs.target.wants
| |-- sockets.target.wants
| |-- sysinit.target.wants
| `-- timers.target.wants
`-- user

-d フラグはディレクトリのみを一覧表示するためのものであり、 -L の後の数字は、指定されたパス(最後の引数)の下の深さのレベルを示します。

ネイティブLinuxファイルシステムでは、各ディレクトリに次の固有の関連情報があります。

  • (自己iノード参照)
  • .. (上位レベルのディレクトリiノード参照)
  • 含まれているオブジェクトのリスト

最後のポイントは、ディレクトリのブロックに含まれるものであることに注意してください。ファイル名とそれに関連するiノード番号を含むテーブルです。 実際、これはファイルシステムがファイル名を保存する唯一の場所です。 通常のファイルiノードは名前を保存せず、他のメタデータのみを保存します。

$ debugfs /dev/sda
debugfs 1.46.2 (20-Nov-2021)
debugfs: stat /file.ext
Inode: 666 Type: regular Mode: 0644 Flags: 0x80000
Generation: 890607921 Version: 0x00000000:00000001
User: 1000 Group: 0 Project: 0 Size: 166
File ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x61a50568:29f85c40 -- Mon Nov 29 18:52:56 2021
atime: 0x61a5055f:8491b840 -- Mon Nov 29 18:52:47 2021
mtime: 0x61a5055f:8491b840 -- Mon Nov 29 18:52:47 2021
crtime: 0x61a5055f:8491b840 -- Mon Nov 29 18:52:47 2021
Size of extra inode fields: 32
Inode checksum: 0x6af32853
EXTENTS:
(0):1064843

上記で確認できるように、ファイル名はiノードデータの一部ではありませんが、statコマンドはわかりやすくするためにファイル名を追加します。

リンクを介して、より複雑なツリー構造を作成できます。

5.3. リンク

実際にデータを複製せずに、ファイルシステムオブジェクトを同時に複数の場所に存在させたい場合があります。 このような場合、リンクを使用します。

実際、別のオブジェクトへのショートカットのようなリンクを考えることができます。 リンクには、ハードとソフト(シンボリック)の2種類があります。

ソフトリンクは現在の名前で元のオブジェクトを直接指しますが、ハードリンクはそのiノードに接続されており、同じファイルの単なる別の名前です。 これは、ファイル名が存在する場所に関する以前のステートメントの例外です。シンボリックリンクもファイル名を保持します。 実際には、シンボリックリンクは常にハードリンクを指しているため、すべてのハードリンクが削除されると、オブジェクトは表示されなくなります。 興味深いことに、シンボリックリンクには独自の特別なiノードがあります。

さらに、ファイルリンクだけでなく、ディレクトリへのリンクも作成できます。 これを行うと、ディレクトリツリーから複雑な円形構造を作成できます。

さらに、iノードメカニズムは特定の動作を引き起こす可能性があります。これについては次に説明します。

6. iノードファイルシステムの詳細

iノードに基づくファイルシステムを使用する場合、その内部動作を考慮する必要がある場合があります。 いくつかの特殊なケースを見てみましょう。

6.1. 最大iノード

空き領域があるにもかかわらず、ファイルシステムでiノードが不足する可能性があります。 これは通常、多くの小さなファイルがあまり多くのストレージを使用しない場合に発生しますが、iノードの総数から差し引かれます。

実際には、 df (ディスクフリー)コマンドを使用して、iノードの総数情報を確認できます。

$ df -ih
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda 16M 106K 16M 1% /

上記の出力は、1600万の可能なiノードのうち10万6000を使用したことを示しています。 もちろん、iノードを解放してより多くの利用可能にすることができます。

6.2. 再割り当て

iノードを削除すると、ファイルシステムは将来別のファイルにiノードを割り当てることができます。 ただし、ファイルを名前で削除することは、iノードを削除することと同じではありません。 前者はポインタ(ハードリンクまたはソフトリンク)のみを削除し、後者はiノードテーブル内のファイルに関するメタデータを破棄します。 このように考えてください:

  • ファイルは、iノードにリンクされた単なる名前です
  • iノードは、ファイルの説明とそのコンテンツブロックポインタで構成されます
  • ブロックはファイルの内容を保持します

したがって、iノードテーブルをスキャンして削除されたファイルを復元することはできますが、通常の状況ではiノードのメタデータに対して同じことを行うことはできません。 ただし、ブロックポインターを失っても、データが永続的に書き換えられる前に、スキャンといくつかの検出アルゴリズムを介して元に戻すことができる場合があります。

6.3. インラインファイル

ファイルシステムで時々利用できるもう1つの便利な機能は、インラインファイルです。 必須のiノードメタデータのサイズがiノードサイズよりも小さい場合に使用できます

$ debugfs /dev/sda
debugfs 1.46.2 (20-Nov-2021)
debugfs: stat /file.ext
Inode: 666 Type: regular Mode: 0644 Flags: 0x80000
Generation: 890607921 Version: 0x00000000:00000001
User: 1000 Group: 0 Project: 0 Size: 166
File ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x61a50568:29f85c40 -- Mon Nov 29 18:52:56 2021
atime: 0x61a5055f:8491b840 -- Mon Nov 29 18:52:47 2021
mtime: 0x61a5055f:8491b840 -- Mon Nov 29 18:52:47 2021
crtime: 0x61a5055f:8491b840 -- Mon Nov 29 18:52:47 2021
Size of extra inode fields: 32
Inode checksum: 0x6af32853
EXTENTS:
(0):1064843

上記の例では32バイトの追加スペースにはデータを含めることができ、非常に小さいファイルの場合、これはデータとメタデータを格納するために追加のディスクスペースを必要としないことを意味します。 この機能は最近(2016年5月)のものであり、e2fsprogsを介して明示的に有効にする必要がある場合があります。

6.4. statおよびdebugfsstat

debugfsのstatからの情報のほとんどは、statコマンドからの情報と同じですが、いくつかの違いがあります

そのうちの1つは世代番号です。 クライアントとサーバーなど、2つの異なるオペレーティングシステムで見られるiノード番号を区別できます。 これらの違いが理にかなっている特定のシナリオでこれを使用します。

もう1つのグループは、フラグメントフィールドです。 これらは、ブロックが廃止されたブロックフラグメンテーション機能をいつ使用するかを示します。

最後に表示されるフィールドはEXTENTSです。 これは、ファイルシステムがシーケンスの最初と最後のブロックの識別子のみを含む連続したブロックを格納できるようにする機能を有効にしたときに発生します。

7. 概要

この記事では、iノードとファイルシステムにおけるそれらの主な役割について説明しました。 そのために、iノード内の情報が不可欠である複数のレベルを調べました。

結論として、 iノードは、ユーザーが表示するファイルと、システムがそれらのファイルについて実際に保存するものの間の接着剤です。