0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unix ファイルシステムについて

Last updated at Posted at 2025-01-25

はじめに

最初の記事の項目のファイルシステムについて
本記事を通じて学んでいきたいと思います。

ゴール

Unixシステムのファイルシステムの構造について理解する。

ファイルシステムについて

ファイルシステムとは、コンピュータリソースを操作する為のOSが持つ機能です。
今回はファイルシステムの中でも
Linuxでのデファクトスタンダードとなっているext4について確認したいと思います。

ext4ファイルシステムの構造について

データを記憶する為には、記憶装置が必要です。
記憶装置としては、SSDだったり、HDDが使用されます。
これらをシステムで使用する際は、パーティションという区間分けをして使用します。
ファイルシステムではこの区間分けされたパーティションを使用します。(以降はext4として記載しています)
パーティションの中には、ブートブロックと、いくつかのブロックグループが存在します。
ブロックグループの中には、スーパブロック、グループディスクプリタテーブル(GDT)、
GDTの予約領域、i-nodeビットマップ、データビットマップ、i-nodeテーブル、データブロックで構成されています。

image.png

ブートブロック:ファイルシステムは使用しない。OSの起動情報が記録される。
スーパブロック:i-nodeテーブルのサイズ情報や論理ブロックサイズ、論理ブロック数が記録される。
GDT:データとi-nodeのビットマップの位置、i-nodeテーブルの位置情報が記録される。
i-nodeビットマップ:i-nodeテーブルでどのエントリが使用されているか記録される。
データビットマップ:ブロックグループ内のデータブロックの使用状況が記録される。
i-nodeテーブル:1エントリにファイルの種別、パーミッション情報、サイズ、データの場所が記録される。
データ領域:ファイルの実データが記録される。

各種領域のダンプを確認してみます。

ブートブロック、スーパブロックのダンプ

image.png

最初の1024バイトはブートブロックであり、使用されていないのがわかります。
アドレス0x400からがスーパブロックの領域になります。
どの情報がどこにマッピングされているかについては、公式に記載されています。

スーパブロック以降はグループディスクプリタテーブルの領域となります。
エントリー数について、スーパブロックのダンプ情報から値を算出してみます。
算出方法は以下になります。

blocks_count(ブロック数) / blocks_per_group(グループ毎のブロック数)

blocks_countは0x8000であり、blocks_countは0x10000000である事から、
8192個のエントリーがある事がわかります。
各エントリーは64バイトで構成されるので、64*8192/4KiB = 80ブロック分使用している事がわかります。
それでは、グループディスクプリタとグループディスクプリタの予約領域を含めてダンプして確認してみます。

グループディスクプリタとグループディスクプリタの予約領域のダンプ

グループディスクプリタはアドレス0x1000から始まります。
グループディスクプリタテーブルの予約領域については、80ブロック x 0x1000(4KiB) + 0x1000から始まります。

image.png

image.png
予約のブロック数は、スーパブロックのs_reserved_gdt_blocksの情報で確認できます。
値を確認すると0x400とわかるので、0x400000分が予約領域で使用されている事わかります。
では、この調子でdataブロックのビットマップを確認してみます。

dataブロックのビットマップのダンプ

アドレス0x400000+0x80000+0x1000からが、dataブロックビットマップとなります。
image.png
※スーパーブロックのbitマップブロックの位置と一致しているのも分かります。

i-nodeブロックのビットマップのダンプ

スーパブロックのi-nodeブロックビットマップの位置である、アドレス0x1481000も確認してみます。

image.png

公式に記載されているブロックレイアウトと同じではいようです。
レイアウトではdataビットマップの1blockの後にi-nodeブロックが続きますが、
dataビットマップの隣は次のブロックグループのdataビットマップとなっています。

i-nodeテーブルのダンプ

i-nodeテーブルについても同じくスーパブロックの情報を確認して、0x2481000からi-nodeテーブルが記録されている事がわかります。
お試しで、サンプルファイルのi-nodeを確認し、該当箇所のdumpを確認してみます。
i-node情報を取得するには、statコマンドを使用します。

kenta@DESKTOP-RNUJ2RM:~/work/practice/qiita$ stat sample2.c
  File: sample2.c
  Size: 990             Blocks: 8          IO Block: 4096   通常ファイル
Device: 820h/2080d      Inode: 6736        Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   kenta)   Gid: ( 1000/   kenta)
Access: 2025-01-22 22:10:36.866980000 +0900
Modify: 2025-01-11 16:56:10.855039947 +0900
Change: 2025-01-11 16:56:10.865039946 +0900
 Birth: 2025-01-11 16:56:10.855039947 +0900

statで出力されるi-nodeの番号は10進数表記されています。

i-node番号の16進数の1A50から-1を引いた値に対して、0x100分掛けます。
(i-nodeの構造体のサイズが256バイトの為)、計算した値から、0x2481000分進めた位置をdumpしてみます。
0x2481000 + 0x1A4F00 = 0x2626000
image.png
最初の4バイトはファイルの種別とパーミッションがエンコードされています。
ext4はリトルエンディアンで記録されるので、0x81a4がエンコードの値になります。
これは通常ファイルで、パーミッションがrw-r--r--である事を表してます。
また、サイズは0x3deで990バイトで、リンクカウントが1になっています。
実際に確認してみます。
image.png
合ってそうですね。
また、i-nodeを確認するとデータが記録されている箇所も確認する事ができます。
ext4からファイルのデータブロック位置をextentツリーで管理されています。(extentは複数ブロックの塊を指します。)

dataブロックのダンプ

先程のi-nodeダンプから、i-blocksを確認すると、extetntが指すブロック番号を確認できますが、
Dataブロックがどこから開始されるのかちょっとわからなかったので、
今回はdebugfsとstatを使用してアドレスを確認します。

sudo debugfs -R "stat /home/kenta/work/practice/qiitasample2.c" /dev/sdc

Inode: 6736   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 500734895    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 990
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x6782241a:ce3dd928 -- Sat Jan 11 16:56:10 2025
 atime: 0x6794d0d3:58140d6c -- Sat Jan 25 20:53:55 2025
 mtime: 0x6782241a:cbdb7f2c -- Sat Jan 11 16:56:10 2025
crtime: 0x6782241a:cbdb7f2c -- Sat Jan 11 16:56:10 2025
Size of extra inode fields: 32
Inode checksum: 0x5f5f7639
EXTENTS:
(0):2127365

statで出力されるEXTENTSの値は10進数表記されています。

EXTENTSの数値はブロック数を表しているので、該当アドレスは0x207605000です。
dumpして中身を確認してみます。
image.png

合っているかファイルの中身を確認してみます。

kenta@DESKTOP-RNUJ2RM:~/work/practice/qiita$ cat sample2.c
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFFER_SIZE (4*1024)
//#define BUFFER_SIZE (1024*1024*1024)

char buffer[BUFFER_SIZE] = {};

int main(int argc, char* argv[])
{
        int fd;
        int r;

        if((fd=open("dummy", O_CREAT|O_WRONLY|O_TRUNC)) == -1){
                fprintf(stderr, "open error\n");
                exit(-1);
                                            }

        r = write(fd, buffer,BUFFER_SIZE);
        if(r != BUFFER_SIZE){
                fprintf(stderr, "write error");
                exit(-1);
        }

        if(argc > 1){
                int opt;
                switch(opt = getopt(argc, argv,"sf")){
                        case 's':
                                printf("sync\n");
                                sync();
                                break;
                        case 'f':
                                printf("fsync\n");
                                if(fsync(fd) == -1){
                                        fprintf(stderr, "fsync error");
                                        exit(-1);
                                }
                                break;
                        default:
                                break;
                }
        }
        return 0;
}

合ってそうですね。

i-blocksですが、シンボリックファイルの場合はextentの情報ではなくファイル名が格納されます。

ディレクトリのダンプ

先程はサンプルファイルの中身を確認しましたが、次はディレクトリの中身も確認したいと思います。
同じく、debugfsとstatを使用してアドレスを確認します。
image.png
該当のExtetentの場所をdumpしてみます。
image.png

対象のディレクトリは以下です。
image.png

ディレクトリの中身には3つのエントリがあります。
※「.」と「..」はディレクトリ作成時に必ず作成されます。
最初の4バイトはi-node番号を指し、次の2バイトはディレクトリエントリの長さ、
次の1バイトはファイル名の長さ、次の1バイトはファイルタイプ、次はファイル名の長さ分の文字列(ASCII)が記録されます。
(ここでファイルタイプが入っているのは、トラバーサル中にi-nodeを参照せずにファイルタイプが参照できるようにする為にファイルタイプが入っています。)
dump情報を確認すると、「.」はi-node番号0x13d5であり、「..」はi-node番号0x61c6であり、
「test1」はi-node番号0x19f2である事が確認できます。
statで「test1」を確認するとi-nodeが実際に0x19f2である事がわかります。

kenta@DESKTOP-RNUJ2RM:~/work/practice$ stat sample/test1
  File: sample/test1
  Size: 5               Blocks: 8          IO Block: 4096   通常ファイル
Device: 820h/2080d      Inode: 6642        Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   kenta)   Gid: ( 1000/   kenta)
Access: 2025-01-25 23:18:16.059327946 +0900
Modify: 2025-01-25 23:18:16.059327946 +0900
Change: 2025-01-25 23:18:16.059327946 +0900
 Birth: 2025-01-25 23:18:16.059327946 +0900

ディレクトリはファイル名とi-nodeを紐づけて記録しているだけですね。

最後に

ファイルシステムの構造について、
中身も含めて確認する事で公式のサイトの内容をなぞりながら理解できるので、
読むだけより、より各種データ項目の意味等が理解できました。
ではまた次回~!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?