Solaris で擬似ファイルシステムをつくろう/其の2 (FTPファイルシステム)目次†ご注意†ここで紹介しているプログラムは、カーネルモジュールを含んでいます。そのため、プログラム上に問題があった場合(可能性大)にはシステムが PANIC し、場合によってはファイルシステムに重大な障害を引き起こす可能性があります。以下のプログラムはテストプログラムで、十分な検証を行ってはいません。したがってあくまで個人の検証ためにお使いいただき、重要なシステム上では動作させないでください。本プログラムの使用により発生したトラブルなど、いかなる損害についても一切の責任を負いかねます。ご利用は自己責任にてお願いいたします。 概要†「Solaris で擬似ファイルシステムをつくろう/其の1」で作成した擬似ファイルシステムをもとに、FTP プロトコルを使って
リモートホストのディレクトリをマウントしてローカルファイルのようにアクセスできる FTP ファイルシステムを作成いたしました。イメージ的には NFS のようなものですが、プロトコルとして FTP を使用しますので、リモートホストが NFS で
ディレクトリを share していなくても、FTP サーバが稼動していてなおかつその FTP サーバのユーザアカウントを持っている
のであれば、リモートホストの任意のディレクトリにマウントし、ファイルにアクセスすることができます。
ソースファイルとダウンロード†
各ソースコードは以下からも参照いただけます。 動作確認済み Solaris バージョン†OpenSolaris 対応の変更を行った後(2010/4/29) の iumfs ファイルシステム の動作確認状況は以下のようになっています。
プログラムの解説†この FTP ファイルシステムは2つのプログラムで構成されています。1つははカーネルモジュールであるファイルシステムモジュール兼仮想デバイスドライバ、もうひとつはユーザモードのデーモンです。ファイルシステムモジュール自身はユーザプロセスからの read(2) などのシステムコールを受け付けるだけで、実際の FTP プロトコルを使った通信部分はユーザモードのデーモンで行っています。ユーザモードのデーモン(iumfsd)と、ファイルシステム(iumfs) との連絡用に仮想デバイスを作成し、この仮想デバイス(/dev/iumfscntl)経由でユーザモードデーモンとファイルシステムのデータの受け渡しが行われるようになっています。 IUMFS ファイルシステムモジュール†ファイルシステムとしての基本的な枠組みは「Solaris で擬似ファイルシステムをつくろう/其の1」のコードをその
まま流用しています。 iumfs_readdir() の変更†iumfs_readdir() は getdents(2)システムコールに対応した VNODE オペレーションで、ユーザプロセス
からの要求にしたがって、ディレクトリエントリを返す関数になります。 iumfs_getattr() の変更†iumfs_getatt() は ファイルのサイズ、変更日、パーミッションなどの属性値を得るための VNODE オペレーションです。 iumfs_read() の変更と、iumfs_getpage() 追加†其の2での一番大きな変更点は VOP_GETPAGE(ページ取得)の実装です。
其の1の IUMFS ファイルシステムではファイルの全内容はカーネルメモリ空間に常に保持されており、
ユーザプロセスからの読み込み要求(read(2)システムコール)に従って VNODE オペレーションである
iumfs_read() 関数がメモリの内容をユーザプロセスに返していただけでした。しかし其の2では
iumfs_read() は seg_map セグメントドライバが提供する segmap_getmapflt() という関数を使って
ファイルをカーネルアドレス空間にマップすることだけを行います。実際のデータの読み込み
は、マップされたカーネルアドレスがアクセスされ、ページフォルトが発生した時点で seg_map セグメント
ドライバから呼ばれる GETPAGE VNODE オペレーション(iumfs_getpage) 内で行われます。 ページキャッシュ†其の2のファイルシステムではファイルデータの読み込みは FTP プロトコルを使ってリモートホストからブロック単位
でファイルを読み込むことで行い、基本的にはローカルシステム上ではファイル全体のコピーは保持しません。 iumfscntl デバイスへのリクエスト†前述の iumfs_readdir, iumfs_getattr, iumfs_getapge といった関数は、その中で iumfscntl デバイスドライバに対して各々の VNODE オペレーションに対応したリクエストを要求します。
iumfscntl デバイスへのリクエストを要求するそれぞれの関数(iumfs_request_xxx) は 必ず以下の関数を順番どおりに呼びだすようにしており、複数のリクエストが同時に 実行されないことを保証しています。
もしいずれかのリクエストがあるスレッドにて処理中であれば、他ののスレッドは iumfs_daemon_request_enter() の 中で cv_wait_sig(9F) で待たされます。 iumfscntl デバイスドライバ†其の1には無かった仮想デバイス /dev/iumfscntl のデバイスドライバです。
iumfscntl ドライバ自身は IUMFS ファイルシステムから渡されたリクエストの中身や、iumfsd デーモンから
渡されたファイルデータの中身は頓着していません。ただ中継するだけです。 ちなみに、IUMFS ファイルシステムモジュールと iumfscntl デバイスドライバはインストールされるファイルとしては 同一のファイル(ハードリンク)になっていますが、カーネルにロードされた後では別々の モジュールとして認識されます。 # modinfo |grep -i iumfs 190 7bfb9cc8 3828 24 1 iumfs (file system for iumfs) 190 7bfb9cc8 3828 148 1 iumfs (control driver for iumfs) iumfd ユーザモードデーモン†socket(3socket) をつかって実際のリモートホストと FTP の通信を行うユーザモードデーモンです。
なお、データセッションについては PASVモード(パッシブモード)のみのサポートとなります。 属性情報の読み込み(NLST)†上記表の NLST コマンドで使っている「-a」や「-dlAL」といったオプションは、激しく FTP サーバ側の実装依存になります。 また -l で取得できるファイルの属性情報(といっても /bin/ls -l の出力と等価)の出力フォーマットも FTP サーバ側に 依存します。現在 iumfsd が認識できる NLST -a の出力フォーマットは以下の8種類になります。
世には多くの GUI の FTP クライアントソフトが存在し、どの FTP クライアントも同様の問題を持っている はずだとおもうのですが、みなさんどのようにファイルの属性情報をプログラム側で取得しているので しょう・・単に多くのフォーマットに対応するようにしているだけなのでしょうか? それとも FTP サーバの 実装に依存せずファイルの属性情報をとってくるコマンド等があるのでしょうか・・・? 私には調べきれませんでした。 ちなみに、NLST の「-d」オプションははディレクトリ中身ではなく、ディレクトリ自身の情報を見るために利用しているのですが、マイクロソフト Windows の FTP サーバでは「-d」オプションを期待通りに認識してくれないようです。そのため、Windows の FTP サーバをマウントした場合、ディレクトリの属性が正しく取れません。要改善・・ですがどうすればいいんでしょう? ファイルデータの読み込み(RETR)†ファイルデータの読み込みではファイルシステムという性質上ブロックモードにてブロック単位で任意の長さの
データをとってきたいところです。しかし多くの FTP サーバではストリームモードしかサポートしていないようです。
つまり、ファイルの 100バイト目から 300バイト目までの 200 byte だけを読み込みたいのに、RETR コマンド
を使うとファイル全体を読み込んでしまうのです。これはかなり非効率的です。
ABORT コマンドを発行したとしても、実際の転送が終了されるまでには相当量のデータがデータセッション を通じて流れてきてしまうためやはり非効率なのは否めませんが、ファイル全体を毎々読み込むことに比べれば だいぶ無駄は少ないと考えています。また、ファイル全体を読む必要がある場合(cp コマンドなど)でも、 かならず 8K バイト単位でデータをとりにいきますのでパフォーマンスはすごく悪いです。 同時実行性†このデーモンはシングルプロセスかつシングルスレッドです。なので、一時に処理できるのは1つの処理
だけです。(たとえば、ホストA 上の /var/log/syslog ファイルを 8K バイト読む。など)
IUMFS ファイルシステム用 mount コマンド†IUMFS ファイルシステム専用の mount コマンドです。 # mount -F iumfs -o user=root,pass=hoge ftp://srv.example.com/export/ /mnt ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ オプション リソース マウントポイント mount コマンド内では渡されたオプションやリソース部分の構文チェックを行い、構文として正しければ
mount(2) システムコールを通じて IUMFS ファイルシステムの iumfs_mount() に全引数を渡します。 インストール†コンパイル&インストール†configure, make 実行すると環境に応じて 64bit/32bit のファイルシステムモジュール兼、擬似デバイスドライバである iumfs モジュールと、mount コマンド、iumfsd デーモンが作成されます。 コンパイル終了後、make install にてファイルのコピーと、ファイルシステムモジュールのカーネルへのロードが行われます OpenSolaris での実行例) # ./configure checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking for a BSD-compatible install... /bin/ginstall -c checking for isainfo... yes configure: creating ./config.status config.status: creating Makefile # make gcc -c -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 -mcmodel=kernel -mno-red-zone -D_KERNEL -I. iumfs.c -o iumfs.o gcc -c -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 -mcmodel=kernel -mno-red-zone -D_KERNEL -I. iumfs_vnode.c -o iumfs_vnode.o gcc -c -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 -mcmodel=kernel -mno-red-zone -D_KERNEL -I. iumfs_cntl_device.c -o iumfs_cntl_device.o gcc -c -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 -mcmodel=kernel -mno-red-zone -D_KERNEL -I. iumfs_request.c -o iumfs_request.o ld -dn -r iumfs.o iumfs_vnode.o iumfs_cntl_device.o iumfs_request.o -o iumfs gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 iumfs_mount.c -o mount gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 iumfsd.c -lsocket -lnsl -o iumfsd gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 fstestd.c -lsocket -lnsl -o fstestd gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -g -O2 -Wall -DOPENSOLARIS -DSOL10 -m64 fstest.c -o fstest # make install /bin/ginstall -c -m 0644 -o root -g sys iumfs /kernel/fs/amd64 /bin/ginstall -c -m 0644 -o root -g sys iumfs.conf /usr/kernel/drv /usr/bin/ln /kernel/fs/amd64/iumfs /usr/kernel/drv/amd64/iumfs /usr/sbin/add_drv iumfs /bin/ginstall -c -d -m 0755 -o root -g bin /usr/lib/fs/iumfs /bin/ginstall -c -m 0755 -o root -g bin mount /usr/lib/fs/iumfs /bin/ginstall -c -d -m 0755 -o root -g bin /usr/local/bin /bin/ginstall -c -m 0755 -o root -g bin iumfsd /usr/local/bin /usr/sbin/devfsadm -t ./iumfs_devlink.tab -i iumfs アンインストール†ファイルシステムモジュールおよびコマンドのアンインストールは make uninstall で行います。 # make uninstall pkill -x iumfsd /usr/sbin/rem_drv iumfs rm /kernel/fs/amd64/iumfs rm /usr/kernel/drv/amd64/iumfs rm /usr/kernel/drv/iumfs.conf rm /usr/lib/fs/iumfs/mount rm -rf /usr/lib/fs/iumfs rm -rf /usr/local/bin/iumfsd iumfsd が動作していない場合以下のようなエラーがでますが問題ありません。 *** Error code 1 (ignored) IUMFS ファイルシステムが利用中(マウントされている)の場合、ファイルの削除は可能ですが、モジュール のアンロードは失敗します。この場合システムのリブート後に完全に削除されます。 # make uninstall pkill -x iumfsd *** Error code 1 (ignored) /usr/sbin/rem_drv iumfs Device busy Cannot unload module: iumfs Will be unloaded upon reboot. rm /kernel/fs/amd64/iumfs rm /usr/kernel/drv/amd64/iumfs rm /usr/kernel/drv/iumfs.conf rm /usr/lib/fs/iumfs/mount rm -rf /usr/lib/fs/iumfs rm -rf /usr/local/bin/iumfsd 使い方†IUMFS ファイルシステムの利用方法についてご説明します。 iumfsd デーモンの起動†IUMFS ファイルシステムからのリクエストに従って FTP の通信を行う iumfsd デーモンを起動しておきます。 Usage: iumfsd [-d level] -d level : デバッグレベル[0-3] デバッグレベルを 1 以上にした場合、フォアグランドで実行され、デバッグメッセージを書き出します。 ファイルシステムのマウント†IUMFS ファイルシステムのマウントには通常の mount(1M) コマンドを利用します。 使い方: mount -F iumfs [-o options] ftp://host/pathname mount_point ftp://host/pathname マウントをする FTP サーバのホスト名と、サーバ上のディレクトリのパスを以下のフォーマットで指定します。 ftp:// 必須 host FTP サーバ名 /pathname サーバ上のディレクトリ。「/」だけでも可。でも省略はできません。 -o options IUMFS ファイルシステム専用のオプションを指定する。現在サポートしているのは以下の2つ。 user=ユーザ名 ユーザ名を指定します。デフォルトは「ftp」。 pass=パスワード ユーザのパスワードを指定します。デフォルトは「ftp」。 mount_point IUMFS ファイルシステムをマウントするマウントポイント 以下に /mnt ディレクトリに srv.example.com の上の /export ディレクトリをマウントする例を示します。(ユーザ名 をhoge、パスワードをheheとします。) # /usr/sbin/mount -F iumfs -o user=hoge,pass=hehe ftp://srv.example.com/export /mnt # もし、FTP サーバが anonymous アクセスを許可しているならば -o オプションは省略できます。(デフォルトのuser=ftp,pass=ftp が使われます) # /usr/sbin/mount -F iumfs ftp://srv.example.com/export /mnt # 確認 # mount ... ... /mnt on ftp://srv.example.com/export read only/setuid/devices/dev=4840003 on (日) 3月 19 17:30:19 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 可能なファイル操作†ディレクトリの移動、ディレクトリエントリの参照†# cd /mnt # /bin/ls file1 file2 各ファイルの属性情報の参照†# ls -la 合計 3 drwxr-xr-x 1 root root 512 3月 19日 17:55 . drwxr-xr-x 27 root root 1024 3月 19日 23:14 .. -rw-r--r-- 1 root root 54455 3月 19日 17:54 file1 -rw-r--r-- 1 root root 163365 3月 19日 17:55 file2 ファイル属性のうち、ファイルタイプ、ファイルサイズ、ファイルの最終変更日時、 あとパーミッションはオリジナルファイルの情報がそのまま反映されますが、ファイル のオーナー情報だけはリモートホスト側の実際のオーナーに関わらず常にroot:rootと表示されます。 ファイルの読み込み†# head file1 This is a test file This is a test file This is a test file This is a test file This is a test file This is a test file This is a test file This is a test file This is a test file This is a test file # ファイルのコピー†# cp file1 /var/tmp # 不可能な操作†open/read/lseek/getdent以外のファイル操作はほとんどできないと思っていただいてかまいません。 其の2の IUMFS ファイルシステム上のファイルに対してこれら以外の操作を行った場合はエラーが返されます。 ファイルのアクセス権の変更 # chmod 777 file1 chmod: 警告: file1 を変更できません。 ファイルの更新日時を変更 # touch file1 touch: file1 の時間を変更できません。 ファイルのオーナーを変更 # chown nobody file1 chown: file1: 読み取り専用のファイルシステムです。 ファイルに書き込み # cp /var/adm/messages file1 cp: file1 を作成できません: 読み取り専用のファイルシステムです。 ファイルシステムのアンマウント†IUMFS ファイルシステムのアンマウントには通常の umount(1M) コマンドを利用します。 Usage: umount mount_point mount_point : ファイルシステムがマウントされているマウントポイント 他のファイルシステムでもおなじですが、だれかがそのファイルシステム上のファイルを 利用中の場合には BUSY が返り、umount(1M) は失敗します。 アンマウントの成功例) # umount /mnt # ファイルシステムが利用中である為にアンマウントが失敗する例) # pwd /mnt # umount /mnt umount: /mnt 使用中です。 今後の課題†
|