tmpfs の謎 |
||
SunOS 4.1.4 | YAMAMORI Takenori |
Solaris 2.x/7/8/9 などの SunOS 5.x系では、tmpfs はデフォルトで使用されますが、SunOS 4.1.4 では、tmpfs はデフォルトでは使用されず、tmpfs を使うための設定は、OS のインストール直後の /etc/rc.local の中ではコメントアウトされています。
そこでまず、稼働中の SunOS 4.1.4 で、実際に tmpfs を使っているかどうか確認する必要があります。 以下のようなコマンドの出力が得られれば、tmpfs が使われています。
$ mount -p | grep swap swap /tmp tmp rw 0 0 $ df | grep swap swap 90196 32 90164 0% /tmp |
もし、tmpfs が使われていなかった場合は、/etc/rc.local
の中に書かれている
# mount /tmp
のコメントを外し、ついでに安全のため、
mount -v /tmp; chmod +t /tmp
と +t フラグを立てるように書き換え、さらに /etc/fstab
の中に、
swap /tmp tmp rw 0 0
という行を追加します。これでリブートすれば(または直接 mount /tmp
を実行すれば) tmpfs が使われるようになります。
SunOS 4.1.4 の3種類の tmpfs のバグとその解決方法を順に説明します。
tmpfs 上に mknod コマンドで FIFO を作成し、これをハードリンクしようとするとカーネルが panic します。
$ cd /tmp $ mknod aaa p $ ln aaa bbb # must be hard-link (not symbolic-link) $ ls -l BAD TRAP: |
これを解決するための SunOS 4.1.4用の patch は何故か出ていません。しかし、SunOS 4.1.3用、または SunOS 4.1.3_U1用の patch は出ているため、これを SunOS 4.1.4 に敢えて当てて使用します。
ファイルは、
100507-06 (SunOS 4.1.3用) または、
102396-01 (SunOS 4.1.3_U1用) の中の、
tmp_vnodeops.o のみを使います。
patch の中には、他にも tmp_*.o というファイルが入っていますが、これらは、すでに SunOS 4.1.4 には統合済みだったり(リリースノートによると100507-05 までは統合済み)、別の patch で更に置き換わるため、 必要ありません。
tmp_vnodeops.o を置き換えてカーネルを再構築すれば 「FIFO ハードリンクのバグ」は解決します。
次のように、tmpfs をカレントディレクトリとした状態で、そのディレクトリを削除し、 その後、その削除されたディレクトリに書き込みを行ない、 さらにほかのディレクトリに移動しようとするとカーネルが panic します。
$ mkdir /tmp/aaa $ cd /tmp/aaa $ rmdir /tmp/aaa $ touch bbb $ cd / assertion failed: tp->tn_dir == NULL |
- ・ここまでの tmpfs 関係の patch と、カーネルオブジェクトのまとめ
tmp_dir.o -- 103314-01 の tmp_dir.o で置き換え tmp_subr.o -- SunOS 4.1.4 オリジナルのまま tmp_tnode.o -- SunOS 4.1.4 オリジナルのまま tmp_vfsops.o -- SunOS 4.1.4 オリジナルのまま tmp_vnodeops.o -- 100507-06 または 102396-01 の tmp_vnodeops.o で置き換え
次のように、tmpfs 上の書き込み禁止のディレクトリに対して シンボリックリンクを作成しようとするとカーネルが panic します。
$ cd /tmp $ mkdir aaa $ chmod -w aaa $ cd aaa $ ln -s bbb ccc # must be symbolic-link (not hard-link) panic: kmem_free: block already free |
この「書き込み不可シンボリックリンクのバグ」については、今現在もまだ patch が出ていません。
(以前は、workaround のためのプログラムを、カーネルに modload して解決したりもしました)
今、新たに、adb で、カーネルの問題の部分を修正し、バグを解決する方法を紹介します。 おそらくこれが「書き込み不可シンボリックリンクのバグ」の完全な解決になっていると考えられます。
vmunix を adb で見て、以下の部分に注目して下さい。
tmp_symlink+164?i _tmp_symlink+0x164: call _tmp_memfree |
書き込み不可のディレクトリに、シンボリックリンクを作ろうとすると、 この部分を通ります。しかし、この時点で tmp_memfree() を呼ぶ必要はなく(すでに kmem_free されている)、この call 命令がバグの原因と判断しました。
これを nop で置き換えればバグが解決することを確認しています。
実際には、vmunix のバイナリ自体は修正せず、SunOS のブート時に以下のようなスクリプトを /etc/rc.local などから起動して、メモリにロードされたカーネルを書き換えるという方法が 安全だと思います。
#!/bin/sh set - `echo 'tmp_symlink+164/i' | adb -k /vmunix /dev/mem | tail -1` if [ "$1" = '_tmp_symlink+0x164:' -a "$2" = 'call' -a "$3" = '_tmp_memfree' ] then echo \ 'tmp_symlink+164/i /W1000000 /i' | adb -k -w /vmunix /dev/mem else echo "$@" '-- not call _tmp_memfree' fi |
以上で「書き込み不可シンボリックリンクのバグ」も解決し、これで SunOS 4.1.4 の3種類の tmpfs のバグがすべて解決しました。
これら tmpfs のバグについて、正式な patch が出ることを望みたいものです。 また、いつか将来、SunOS 4.1.4 のソースが公開された場合には、自分で再度、上記バグの原因を検証したいとも 思っています。