I.はじめに
このセクションの冒頭では、Linuxファイルシステムを分析します。すべてがLinuxのファイルであるという考えはよく知られており、そのファイルシステムはキャラクターデバイス、ブロックデバイス、パイプ、プロセス間通信、ネットワークなどに不可欠な知識であるため、その重要性は想像できます。この記事では、最初にファイルシステムの基本を紹介し、次に最も重要な構造inode
とその上に構築された階層化ファイルシステムを紹介します。
2.ファイルシステムの基本的な知識
すべてが要件を満たすように設計されているため、ファイルシステムに必要な基本機能から設計する方法を検討します。まず、ファイルシステムには次の基本的な要件が必要です。
- ファイルは読み書きが簡単で、名前の競合などを回避する必要があります。
- ファイルは簡単に見つけ、整理し、分類する必要があります
- オペレーティングシステムには、管理用のドキュメント機能が必要です。
したがって、ファイルシステムは次の特性で設計されています。
- ツリー構造とフォルダー設計を採用
- 読み書きが簡単なホットファイルをキャッシュする
- インデックス構造を使用して、分類を見つけやすい
- 一連のデータ構造を維持して、どのドキュメントがどのタスクで使用されているかを記録する
この基本設計に基づいて、Linuxの広範でスピリチュアルなファイルシステムをゆっくりと検討し始めることができます。
3. iノードの構造とファイルシステム
3.1ブロックストレージの表現
ハードディスクではブロックを記憶単位として使用しますが、ファイルシステムではブロック情報を格納するための基本的な構造が必要です。これがファイルシステムinode
の要です。ソースコードは次のとおりです。inode
それはindex node
そのインデックスノードを意味します。このデータ構造から、inode
ファイルの読み取りと書き込みの権限i_mode
、ユーザーが所属するi_uid
グループi_gid
、グループ、サイズi_size_lo
、およびブロックの数がわかりますi_blocks_lo
。さらに、ファイルに関連するいくつかの回があります。i_atime
これaccess time
は、ファイルへの最後のアクセスの時刻です。i_ctime
つまりchange time
、最新の変更inode
時刻です。i_mtime
つまりmodify time
、ファイルの変更が最後の時刻です。
/*
* Structure of an inode on the disk
*/
struct ext4_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size_lo; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Inode Change time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks_lo; /* Blocks count */
__le32 i_flags; /* File flags */
......
__le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
......
};
#define EXT4_NDIR_BLOCKS 12
#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
ここでは、以下に焦点を当てる必要i_block
があります。メンバー変数は、実際にはファイルコンテンツの各ブロックを格納します。ext2およびext3形式のファイルシステムでは、最初の12ブロックを使用して対応するファイルデータを保存します。各ブロックは4KBです。ファイルが大きすぎて収まらない場合は、次のいくつかの間接ストレージブロックを使用してデータを保存する必要があります。その貯蔵原理の鮮やかな表現。
このストレージ構造の問題は、大きなファイルの場合、対応するブロックのコンテンツにアクセスするために複数の呼び出しが必要になるため、アクセス速度が遅いことです。このため、ext4は新しいソリューションであるExtentsを提案しました。簡単に言えば、エクステントはツリー構造を使用してファイルブロックを継続的に格納し、アクセス速度を向上させます。一般的な構造を次の図に示します。
[外部リンク画像の転送に失敗しました。ソースサイトにアンチリーチリンクメカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします(img-lB3a7yLE-1596126703207)(https://ars.els-cdn.com/content/image/1-s2 .0-S1742287617300270-gr2.jpg)]
主な構造はノードext4_extent_header
でありeh_entries
、このノードにあるアイテムの数を示します。ここには2種類のアイテムがあります。
- リーフノードの場合、この項目は、ハードディスク上の連続したブロックのアドレスを直接指します
ext4_extent
。これは、データノードと呼ばれます。 - ブランチノードの場合、このアイテムは次のレイヤーのブランチノードまたはリーフノードを指します
ext4_extent_idx
。これをインデックスノードと呼びます。この2種類のアイテムのサイズは12byte
です。
ファイルが小さい場合は、inode
内側i_block
に1 ext4_extent_header
と4を付けext4_extent
ます。したがって、今回eh_depth
は0でinode
、葉ノードがあり、木の高さは0です。ファイルが大きく、4つextent
が収まらないeh_depth>0
場合は、ツリーに分割する必要があります。ノードはiノードであり、inode
中間のルートノードの最大深度です。下部eh_depth=0
はリーフノードです。ルートノードに加えて、他のノードは4k、4k ext4_extent_header
の12の控除内のブロックに保存されbyte
、残りは340を置くことができ、それぞれextent
最大128MBのデータを表すことができ、340 extent
は42.5GBに到達したファイルを示します。これはすでに非常に大きいです。大きい場合、ツリーの深さを増やすことができます。
/*
* Each block (leaves and indexes), even inode-stored has header.
*/
struct ext4_extent_header {
__le16 eh_magic; /* probably will support different formats */
__le16 eh_entries; /* number of valid entries */
__le16 eh_max; /* capacity of store in entries */
__le16 eh_depth; /* has tree real underlying blocks? */
__le32 eh_generation; /* generation of the tree */
};
/*
* This is the extent on-disk structure.
* It's used at the bottom of the tree.
*/
struct ext4_extent {
__le32 ee_block; /* first logical block extent covers */
__le16 ee_len; /* number of blocks covered by extent */
__le16 ee_start_hi; /* high 16 bits of physical block */
__le32 ee_start_lo; /* low 32 bits of physical block */
};
/*
* This is index on-disk structure.
* It's used at all the levels except the bottom.
*/
struct ext4_extent_idx {
__le32 ei_block; /* index covers logical blocks from 'block' */
__le32 ei_leaf_lo; /* pointer to the physical block of the next *
* level. leaf or next index could be there */
__le16 ei_leaf_hi; /* high 16 bits of physical block */
__u16 ei_unused;
};
したがって、inode
一連のブロックを表現してファイルを形成できます。ハードディスクには、シリーズを通して、inode
多数のファイルを保存することができます。しかし、それでもなお、保存および管理する方法が必要inode
です。これはビットマップです。同様に、ブロック情報を管理するためにブロックビットマップを使用します。以下はinode
、作成プロセス中のビットマップへのアクセスを示しています。次の0ビットがどこにあるか、つまり空きinode
位置を見つける必要があります。
struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
umode_t mode, const struct qstr *qstr,
__u32 goal, uid_t *owner, __u32 i_flags,
int handle_type, unsigned int line_no,
int nblocks)
{
......
inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
......
ino = ext4_find_next_zero_bit((unsigned long *)
inode_bitmap_bh->b_data,
EXT4_INODES_PER_GROUP(sb), ino);
......
}
3.2ファイルシステムフォーマット
inode
sumブロックはファイルシステムの最小単位であり、大まかに次のように、その上にマルチレベルシステムがあります。
- ブロックグループ:データを格納する単位
ext4_group_desc
。データ構造はです。inode
ビットマップのグループ用のブロックbg_inode_bitmap_lo
、ビットマップブロックbg_block_bitmap_lo
、対応する定義のinode
リストbg_inode_table_lo
があります。各ブロックグループは、基本的にファイルシステム全体の構造を構成します。 - ブロックグループ記述子テーブル:複数のブロックグループ記述子で構成されるテーブル
- スーパーブロック:ファイルシステム全体が記述される場合、つまり
ext4_super_block
、ファイルシステム全体などのグローバル情報を格納する場合の総数inode
:;s_inodes_count
ブロックの総数:s_blocks_count_lo
各ブロックグループ番号inode
:s_inodes_per_group
各ブロックグループのブロック数:s_blocks_per_group
その他。 - ブートブロック:ファイルシステム全体で、オペレーティングシステムの起動用のブート領域として領域を予約する必要があるため、ブート領域を開始するには、最初のブロックグループの前に1Kを予約する必要があります。
スーパーブロックおよびブロックグループ記述子テーブルはグローバル情報であり、これらのデータは非常に重要です。これらのデータが失われると、ファイルシステム全体を開くことができなくなります。これは、ファイルの1つのブロックの損傷よりも深刻です。したがって、これら2つの部分をバックアップする必要がありますが、戦略は異なります。
- デフォルトの戦略:各ブロックにスーパーブロックとブロックグループの説明テーブルのコピーを保存します
- sparse_super戦略:スパースストレージが採用され、0、3、5、7のブロックグループインデックスの整数乗でのみ保存されます。
- メタブロックグループ戦略:ブロックグループを複数のメタブロックグループ(メタブロックグループ)に分割します。各メタブロックグループのブロックグループ記述子テーブルには、独自のコンテンツのみが含まれます。タプルグループには64個のブロックグループが含まれます。このようなタプルグループのブロックグループ記述子テーブルには、最大64項目があります。このアプローチは似て
merkle tree
おり、スペースを大幅に最適化できます。
3.3ディレクトリの保存形式
ファイルの検索を容易にするために、インデックス、つまりファイルディレクトリが必要です。実際、ディレクトリ自体もファイルですinode
。inode
また、いくつかのブロックを指しています。通常のファイルとは異なり、通常のファイルのブロックはファイルデータを格納し、ディレクトリファイルのブロックはディレクトリ内のファイル情報を項目ごとに格納します。これを情報と呼びますext4_dir_entry
。2番目のバージョンにext4_dir_entry_2
は16ビットの2つのバージョンがありname_len
、8ビットname_len
と8 ビットになりますfile_type
。
struct ext4_dir_entry {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__le16 name_len; /* Name length */
char name[EXT4_NAME_LEN]; /* File name */
};
struct ext4_dir_entry_2 {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT4_NAME_LEN]; /* File name */
};
ブロックカタログファイルで、リストを保存する最も簡単な形式ext4_dir_entry_2
。つまり、列ごとに1つずつ。各アイテムは、ディレクトリの次のレベルにあるファイルのファイル名を保存します。inode
これinode
により、実際のファイルを見つけることができます。最初の項目は「。」で現在のディレクトリを示し、2番目の項目は「...」で上位レベルのディレクトリを示し、次はファイル名と項目inode
です。場合によっては、ディレクトリにファイルが多すぎる場合、このディレクトリでファイルを検索する必要がありますが、リストに従って1つずつ検索するのは遅すぎるため、インデックスモードを追加します。フラグをinode
設定するEXT4_INDEX_FL
と、ファイルディレクトリ構成のブロックが変更され、以下のように定義されます。
struct dx_root
{
struct fake_dirent dot;
char dot_name[4];
struct fake_dirent dotdot;
char dotdot_name[4];
struct dx_root_info
{
__le32 reserved_zero;
u8 hash_version;
u8 info_length; /* 8 */
u8 indirect_levels;
u8 unused_flags;
}
info;
struct dx_entry entries[0];
};
現在のディレクトリと親ディレクトリは変更されず、ファイルリストはdx_root_info
構造に変更されます。最も重要なメンバー変数は、間接的なインデックスレベルの数を示すindirect_levelsです。dx_entry
表現される構造によるインデックスエントリ、マッピング関係は、ファイル名とデータブロックのハッシュ値です。
struct dx_entry
{
__le32 hash;
__le32 block;
};
ディレクトリの下でファイル名を検索する場合は、名前でハッシュを取得できます。ハッシュが一致する場合、このファイルの情報が対応するブロックにあることを意味します。次に、インデックスがないがインデックスツリーのリーフノードである場合、このブロックを開きext4_dir_entry_2
ます。行にファイル名が見つかる限り、リストは1つずつあります。インデックスツリーを使用すると、ディレクトリ内のN個を超えるファイルを多くのブロックに分散させることができ、すばやく検索できます。
3.4ソフトリンクとハードリンクの保存形式
ソフトリンクとハードリンクも一種のファイルで、以下のコマンドで作成できます。ハードリンクを作成ln -s
せずに、ソフトリンクを作成します-s
。
ln [参数][源文件或目录][目标文件或目录]
ハードオリジナルのファイル共有Aへのリンクinode
が、inode
各ファイルシステムは、独自の持っている、クロスファイルシステムではありませんinode
、ファイルシステムにまたがるハードリンクに方法はありませんリストを、。ソフトリンクとは異なり、ソフトリンクはファイルの再作成と同等です。このファイルも独立していますがinode
、このファイルを開いて内部のコンテンツを表示すると、コンテンツは別のファイルを指しています。これは非常に柔軟です。ファイルシステムをまたぐことができます。ターゲットファイルが削除されても、リンクされたファイルは存在しますが、指定されたファイルは見つかりません。
4.まとめ
この記事は、主にファイルシステムの設計の視点から始まり、inode
それに基づいinode
てext4
ファイルシステムの構造と主要コンポーネントを徐々に分析しています。以下は、Geek Timeでの画像の要約です。
ソース情報
[1] iノード
[2] ext4_inode
[3] ext4_extent
参照
[1]ウィキ
[3] woboq
[4] Linuxインサイド
[5] Linuxカーネルに対する深い理解
[6] Linuxカーネル設計の芸術
[7] Geek TimeがLinuxオペレーティングシステムについて語る