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 は取り除いた.