SFS 1.1 と POSIX File System に関する考察
[Up]
SFS 1.1 と POSIX File System に関する考察
Jan. 20, 2002 T. Naniwa
I. sfs
I-1. ディスク構造
sfs はファイル・システムを 512 Byte を 1 block とする block 単位で
扱う.ディスクは先頭から
boot block 1 ブロック
super block 1 ブロック
bitmap block 必要ブロック数
i-node 領域 必要ブロック数
data block 残り
によって構成される.
・i-node の使用状況を示すための bitmap block は持たないことに注意.
また,現在は空き i-node の検索のためにディスク上の i-node 領域が順
に走査される.
I-2. super block の構造
struct sfs_superblock
{
UW sfs_magic;
H sfs_version_hi;
H sfs_version_lo;
UW sfs_mountcount;
H sfs_blocksize;
UW sfs_nblock;
UW sfs_freeblock;
UW sfs_bitmapsize;
UW sfs_ninode;
UW sfs_freeinode;
UW sfs_isearch; /* この番号以下の inode は使用中 */
UW sfs_bsearch; /* この番号以下の block は使用中 */
UW sfs_datablock;
};
・super block のサイズは 46 Byte であり,まだまだ固有の情報を保持
できる.
I-3. i-node の構造
#define SFS_DIRECT_BLOCK_ENTRY 70 /* 35 KB */
#define SFS_INDIRECT_BLOCK_ENTRY 20 /* 1280 KB */
#define SFS_DINDIRECT_BLOCK_ENTRY 26 /* 約 214 MB */
#define SFS_TINDIRECT_BLOCK_ENTRY 1 /* 予約: 約 1 GB */
struct sfs_inode
{
UW sfs_i_index; /* SFS の場合、inode は 1 からはじまる */
UW sfs_i_nlink;
UW sfs_i_size;
UW sfs_i_size_blk;
UW sfs_i_perm;
UW sfs_i_uid;
UW sfs_i_gid;
UW sfs_i_dev; /* not used */
UW sfs_i_atime;
UW sfs_i_ctime;
UW sfs_i_mtime;
UW sfs_i_direct[SFS_DIRECT_BLOCK_ENTRY];
UW sfs_i_indirect[SFS_INDIRECT_BLOCK_ENTRY];
UW sfs_i_dindirect[SFS_DINDIRECT_BLOCK_ENTRY];
UW sfs_i_tindirect[SFS_TINDIRECT_BLOCK_ENTRY]; /* reservation only */
};
・i-node は 512 Byte (1 block) を占有する.
・現在のところ,三重間接ブロック用の領域は予約されているだけで,実
装されていない.そのため,1 つのファイルで保存できるデータの大きさ
は約 214 MB となっている.三重間接ブロックを実装すると約 1.2 GB ま
で扱えるようになる.
・sfs_i_index が i-node の index 番号(1 から始まる)と一致している
ものは使用中である.使用していない sfs_i_index は 0 とする.i-node
の割り当ては i-node 番号と一致するかどうかで判断する.ファイルを削
除する場合には忘れずに sfs_i_index を 0 にしなければならない.
・sfs_i_nlink によってファイル・システムにおけるリンクの数を保持し
ている.以前は i-node がディレクトリを示す場合,ディレクトリ内に含
まれるエントリーの数を表すためにも使われていたが,やめにした.
・sfs_i_size_blk によって block 単位のサイズを保持するようであるが,
現状では特に利用されていない.無くしてしまっても良いと思われたが,
BTRON 3 の仕様のファイル・システムににこのレコードがあるので,残し
ている.
I-4. その他
・ディレクトリ・エントリーの名前の最大長は 14 文字である.padding を利
用して,表示可能文字数が 14 文字になるように処理している.struct
sfs_dir には 2 Byte の padding 用の要素が含まれているので,エントリー
名は 15 文字までにすることが可能である.
・ディレクトリ・エントリーが削除された場合,その領域はディレクトリ・
ファイルから取り除き,ファイルのサイズも縮小する.そのため,一旦削
除したファイルを復活させることはできない.
・ディレクトリへの新しいエントリーの登録は,ディレクトリ・ファイル
の最後エントリーを追加することで実現されている.
・posix/kernel/POSIX/manager/sfs_fs.h を変更した場合,その内容を
boot/2nd/sfs.h にも反映させる必要がある.
・sfs_i_lookup の中で,ファイルのアクセス権とモードのチェックを行
なう必要があるだろう.
II. POSIX ファイル・システム
II-1. i-node
struct inode
{
struct inode *i_prev;
struct inode *i_next;
struct fs *i_fs;
UW i_device;
UW i_lock;
struct iops *i_ops;
W i_refcount;
W i_dirty;
struct inode *coverfile;
/* in disk */
UW i_mode;
UW i_link;
UW i_index;
UW i_uid;
UW i_gid;
UW i_dev; /* if device file */
UW i_size;
UW i_atime;
UW i_ctime;
UW i_mtime;
UW i_size_blk;
/* ここに各ファイルシステムの独自の情報が入る (union で... )*/
union
{
struct sfs_inode sfs_inode;
} i_private;
};
・i_dirty というフラグによって i-node の内容が変更されたかどうか記
録しているが,このフラグを参照するのは fs_close_file() のみである.
本来は dealloc_inode() の中で i_dirty の処理を行なう必要がありそう
だが....
・i_refcount によって i-node の参照数をカウントし,これが 0 になる
と対応する i-node は memory 上から消去される.
・i_next は free inode のリストに含まれているときと,register
i-node のリストに含まれている時の両方で利用される.register i-node
のリストは queue になっており,i_prev も利用する.
・i-node には coverfile という要素があるが,mount point の i-node
には mount したファイルシステムの root i-node を登録しておけば良い.
mount した root i-node に mount point の i-node を登録しておくと,
cd .. で上に上がったときに mount 前の directory の中身が見えてしま
うのでまずい.UMOUNT するときには,この中身を NULL にする.
・i_device は super block の fs_device と同じ情報を冗長に保持して
いる.
II-2. super block (file system)
struct fs
{
struct fs *fs_prev;
struct fs *fs_next;
W fs_magicid;
W fs_typeid;
W fs_refcount;
W fs_rflag;
struct fsops *fs_ops;
W fs_lock;
UW fs_device;
struct inode *fs_ilist; /* 使用中の inode のリスト */
W fs_blksize;
struct inode *rootdir;
struct inode *mountpoint;
W fs_dirty;
W fs_allblock;
W fs_freeblock;
W fs_usedblock;
W fs_allinode;
W fs_freeinode;
W fs_usedinode;
UW fs_isearch; /* この番号以下の inode は使用中 */
UW fs_bsearch; /* この番号以下の block は使用中 */
union
{
struct sfs_superblock sfs_fs;
} fs_private;
};
・sfs の中で super block (fs) を書き換えた後 sfs_syncfs() を呼び出
してディスクへの書き戻しを行なっているが,この為にディスク・アクセ
スが頻発し,パフォーマンスが低下している.ファイル・システムの
sync のタイミングを設計する必要があると思われる.
・fs_ilist はそのファイルシステムで使用中の i-node のリストの保存
に使用する.MOUNT が成功していれば fs_ilist には root inode が必ず
登録されている.
・ファイルシステムがマウントされているときに,マウント先の i-node
を示す情報を mountpoint に保持する.マウントされたシステムの root
i-node はrootdir に保存される.
・あるブロックデバイスが既にマウントされているかどうかは fs
のリストをたどって fs_device をチェックする.
・fs_refcount, fs_lock, fs_rflag は使用されていない.fs_rflag を将
来はファイルシステムの書き込み禁止のフラグに使用する.
II-3. その他
・ファイルのモードが O_RONLY, O_WONLY, O_RDWR と O_CREAT, O_APPEND し
かないが,その他に少なくとも O_TRUNC が必要なのではないか.POSIX に準
拠するには O_EXCL, O_NDELAY も必要だと思われる.
・ファイル記述子(file descriptor)の 0, 1, 2 は init の登録時に標準
入力,標準出力,標準エラー出力に割り当てられる.実際のデバイスファ
イルをオープンするのではなく,仮想的に i-node を割り当てている.
・標準のファイルの i_mode (sfs だと sfs_i_perm に保存される) には
SFS_FMT_REG をセットする.
・スペシャルファイルのデバイス番号(major, minor) は sfs_i_direct[0]
に保存される.
・process.c で,各プロセスが独自の file table を持っているが,ファ
イルを共有することを考えると,file table は一つにして,各プロセス
は tableの index を持つようにするべきではないか.
・ファイルを共有する場合に,file offset も共有させるのか? 現在はファ
イルディスクリプタ毎に異なる offset 情報を持つ.dup/dup2 でコピー
されたファイルディスクリプタでは offset は 0 に戻されている.MINIX
では file offset を保存するための table をプロセスとは独立に用意し
ている.
・POSIX システム・コールの lseek で EOF を越える場所に移動すると,
新規にファイルを書き込む時点で offset の位置まで 0 を連続して書き
込むようにした.
・fctl の第2引数の request の上位 16 bit には device driver に送る
control command を,下位 16 bit には,第3引数の argp が指す引数のバイ
ト数を入れる.これに対応して,device driver を作成する場合には control
code を 16 bit 以下に納めることを推奨する.
・fctl の第2引数の下位 16 bit が 0 の場合,第3引数が直接 int 型で与
えられると解釈する.しかし,kernel/ITRON/kernlib/device.h の
DEV_REL_CTL で UB param[0] となっているので問題があるかもしれない.し
かし,UB である必要はあるのだろうか?
・UNIX の getdents はそれぞれのエントリーのアラインメントを行っ
ている様だが,ここではアラインメントは行っていない.ただし,
sizeof(struct dirent) でファイル名以外の部分の大きさを計算し
ているところで 1 byte 分余計に計上されている.
・struct dirent の定義は
kenrle/POSIX/manager/posix.hにある.
III. MOUNT/MOUNTROOT システムコールの実装について.
III-1. やるべきこと.
1. メモリー上の super block と i-node のデータ構造の確認と修正.
2. MOUNT システムコールによる super block の読み込みと登録の処理.
3. fs_lookup でマウントポイントを横切る場合の処理の追加.
i-node の coverfile はツリーを下がる場合には有効だが,cd .. で上
がる場合には fs_lookup の中で特別な処理を行うようにする.
4. link システムコールに,ファイルシステムをまたがないようにチェッ
クするルーチンを追加する.
これは i-node の super block へのポインタを比較することで行える.
5. UMOUNT システムコールの実装.
(6. MOUNTROOT システムコールの内容の確認と修正.)
現在の状況では,init 以外のプロセスが MOUNTROOT を発行することは
無いと思われる.
III-2. その他
・root ファイルシステムは rootfs というポインタに保存されている.
新たにファイルシステムをマウントしたら,このポインタに対して fs の
リンクリスト(キュー)を構成する必要がある.
・root ファイルシステムも UMOUNT できるようにして,例えば RAMDISK
を root file system に指定できるようにしたいが,次に MOUNTROOT を
呼び出すときの引数の指定をどうするかに問題がある.現在は UMOUNT は
失敗するようにしてある.
・ファイルシステムの整合性のチェックを強化するには sfs_fs.c の
sfs_mount 内でディスク上の super block の情報をチェックすれば良い.
現在(sfs_mountroot)は magic number だけをチェックしている.
・mount システムコールは,デバイスファイル,マウントするディレクト
リ,オプションの他に,4 番目の引数としてファイルシステムの型を示す
文字列を与える.現在のところ "sfs" のみがサポートされている.Linux
の mount とは引数の順番が違うので,sash を移植する際は修正が必要.
・mountroot システムコールはデバイス番号,fstype (現在 sfs の 1 の
みが有効),option の 3 つの引数を受け取る.option は現在使用されて
いない.また libc や lowlib からは mountroot は取り除いた.