[English Page][Japanese Page]

tmpfs の謎

SunOS 4.1.4
YAMAMORI Takenori


SunOS 4.1.4 の tmpfs には、カーネルが panic する3つのバグがあります。そのうち2つは patch が一応存在しますが、最後の一つ、シンボリックリンクのバグについては、未だに patch が存在しません。ここでは、SunOS 4.1.4 の patch が出ていないバグを含め、tmpfs のバグ3種類すべてに対する解決方法を紹介します。
●まず、tmpfs を使っているかどうかの確認

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 が使われるようになります。


●3種類の tmpfs のバグ

SunOS 4.1.4 の3種類の tmpfs のバグとその解決方法を順に説明します。


○FIFO ハードリンクのバグ

tmpfs 上に mknod コマンドで FIFO を作成し、これをハードリンクしようとするとカーネルが panic します。

How to repeat:

  $ 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 します。

How to repeat:

  $ mkdir /tmp/aaa
  $ cd /tmp/aaa
  $ rmdir /tmp/aaa
  $ touch bbb
  $ cd /

assertion failed: tp->tn_dir == NULL

解決方法:

この「削除ディレクトリ書き込みのバグ」については、SunOS 4.1.4用の patch が出ています。
103314-01 を当てるとバグが解決します。
更新されるファイルは tmp_dir.o です。 (カーネルの再構築が必要です)

・ここまでの 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 します。

How to repeat:

  $ 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 で、カーネルの問題の部分を修正し、バグを解決する方法を紹介します。 おそらくこれが「書き込み不可シンボリックリンクのバグ」の完全な解決になっていると考えられます。

vmunixadb で見て、以下の部分に注目して下さい。


tmp_symlink+164?i
_tmp_symlink+0x164:             call    _tmp_memfree 

書き込み不可のディレクトリに、シンボリックリンクを作ろうとすると、 この部分を通ります。しかし、この時点で tmp_memfree() を呼ぶ必要はなく(すでに kmem_free されている)、この call 命令がバグの原因と判断しました。

これを nop で置き換えればバグが解決することを確認しています。

実際には、vmunix のバイナリ自体は修正せず、SunOS のブート時に以下のようなスクリプトを /etc/rc.local などから起動して、メモリにロードされたカーネルを書き換えるという方法が 安全だと思います。

●tmp_symlink-fix (ブート時に adb を実行するスクリプト)

#!/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 のソースが公開された場合には、自分で再度、上記バグの原因を検証したいとも 思っています。


To 『SunOS 4.1.4 の謎』index

To「謎の処理系 SunOS 4.1.4 with Linux/FreeBSD/Solaris」Home
yamamori