ディスクレスクライアントを作ろう

最終目標は?

24時間電源を入れてFreeBSD(98)を動かしています。 動かしているのは PC-9801FA で、とっても静かなマシンです。 そのため、ハードディスクの回転音が目立ちます。 また容量も200MBと小さいものを使っています。 SS-10も動かしているので、FreeBSD(98)がディスクレスクライアントになれば 静かになるはずです。ついでに、PCで動くFreeBSDとディスクが共有できれば 便利になります。

したがって、最終目標はPCとPC-98x1で出来るだけディスクを共有する ディスクレスクライアントを作ることです。

OSは何にするか?

FreeBSD 3.3 RELEASE ベースの FreeBSD(98) とします (以前に FreeBSD(98)2.2.8-RELEASE で試した時のメモ もあります)。

どうやって起動するか?

起動するには、 といった方法があります。特徴はそれぞれ、 となります。ここでは、フロッピーにBOOTPをサポートしたカーネルを用意し、 そこから起動することにします。

ブートフロッピーを作る

必要なネットワークドライバを組み込んだカーネルを用意します。 BOOTPをサポートするために、configファイルには、
options         BOOTP           # Use BOOTP to obtain IP address/hostname
options         BOOTP_NFSROOT   # NFS mount root filesystem using BOOTP info
options         BOOTP_COMPAT    # Workaround for broken bootp daemons.
を書いておきます。BOOTP_COMPAT がないと、NetBSD/sparc 1.4.1 の bootpd では うまくいきませんでした。
options         "BOOTP_NFSV3"   # Use NFS v3 to NFS mount root
を書いておいてもいいでしょう。 またフロッピーから起動した時、userconfigの情報は覚えてくれない (NFSマウントしたrootディレクトリに情報を書いてくれても起動時には読めない) ので、I/Oアドレスなどは使用するデバイスに合わせておきます。 カーネルが出来たら gzip で圧縮しておきます。
	gzip kernel
以前の kzip は、ELF kernel を扱えないようです。 フロッピーへの書き込みは FreeBSD(98)3.3-RELEASE Rev.01 の kern.flp を用意し、 次のようにして行ないました。
	mount /dev/fd0a /mnt
	cp kernel.gz /mnt
ここで、/mnt/boot/loader.conf を変更しておきます。loader.conf の中身は、 次のようにしました。

変更後、umount します。
	umount /mnt
同じカーネル(gzipしていないもの)をNFSサーバに用意するrootディレクトリに コピーしておきます。フロッピーのkernelと、rootディレクトリのものが 一致していないと、ps -aux, dmesgなどが使えなくなるので注意が必要です。

サーバを用意する

BOOTPサーバ

ここでは、NetBSD/sparc 1.4.1 を使いました。man bootpd を見るとbootpdは デーモンとして常に動かしておく方法と、inetdから起動する方法があるようです。 ここではinetdから起動することにしました。/etc/services, /etc/inetd.confに 必要な記述があることを確認します。つぎに、BOOTP でディスクレスクライアントに 渡す情報を記述します。/etc/bootptabに、
oliv:\
        :ht=ether:\
        :ha=000006001b1a:\
        :sm=255.255.255.0:\
        :hn:\
        :ds=10.93.63.2:\
        :ip=10.93.63.97:\
        :gw=10.93.63.2:\
        :rp="10.93.63.51:/disk2/diskless/oliv-root":\
        :vm=rfc1048:
といったように書きます。各フィールドの意味は書きませんが、 root partitionのフィールドにはNFSマウントのため`:'が含まれています。 これがフィールドの区切りと重なるので、" "で囲んでいます。

NFSサーバ

ここでは、NetBSD/sparc 1.4.4 を使いました。 配布ファイルを順に NFS サーバ上で展開しました。 まず、FreeBSD 3.3-RELEASE の配布ファイルを展開し、 次に FreeBSD(98) 3.3-RELEASE の配布ファイルを別のディレクトリに 展開しました。 FreeBSD, FreeBSD(98)で出来るだけファイルを共有できるように、 順にファイルの入れ換えを行ないました。 / パーティションで i386とpc98で違う(98binを展開すると追加、入れ換えとなる)のは、

/boot/{defaults/loader.conf, boot1, boot2, loader, loader.help, loader.rc,
	loader.4th, support.4th}
/kernel
/kernel.GENERIC98
/dev/MAKEDEV(/dev)
/etc/mtree/BSD.usr.dist, /etc/make.conf, /etc/disktab,
/modules/{atapi.ko, msdos.ko, blank_saver.ko, daemon_saver.ko,
	fade_saver.ko, green_saver.ko, logo_saver.ko, rain_saver.ko,
	snake_saver.ko, star_saver.ko, warp_saver.ko, fire_saver.ko}
/sbin/fdisk
です。/ はi386, pc98で共有しないことにし、上書きします。 /usr の下は、
/usr/bin/(col, more, talk)
/usr/sbin/(fdformat, pnpinfo, tzsetup, vidcontrol)
/usr/include/libdisk.h
/usr/lib/libdisk.a
とXのサーバです。 /usr/share/misc/more.help は、(98)の配布ファイルにはいっていますが、 中身は同じです。 /usr/include/libdisk.h は、#ifdef で括られているので 98bin に 含まれているものに入れ換えてしまいます。 ソースについても98用の追加変更がありますが、 基本的には #ifdef で括られていて入れ換えて問題ないはずです。

col, more, talkは8ビット透過になっているだけのはずなので 入れ換えてしまってもいいはずですが、 /usr/bin, /usr/sbin はwrapperをつくることにします。/usr/bin/pc98, /usr/bin/i386にバイナリを入れ、アーキテクチャによってよびだすものを 変えるスクリプトを用意します。 /usr/sbinも同様にします。/usr/bin用は、このようにしました。

#!/bin/sh

BASENAME=`basename "$0"`
BASEDIR=/usr/bin
SYSCTL=/sbin/sysctl

if [ "`sysctl -n hw.machine`" = "pc-98" ]; then
	exec $BASEDIR/pc98/$BASENAME $@
else
	exec $BASEDIR/i386/$BASENAME $@
fi

libdisk.aは関係するものを コンパイルしなければいいはずです。/usr/libは結構大きいので できれば共有したいところです。

/usr/share/{98readme, FAQ.98, handbook.98}もコピーしておくと便利です。

/etc/exports はディスクレスクライアントからアクセス 出来るようにしておきます。またrootアクセスも許しておきます。 ディスクレス用の、etc/fstab, etc/rc.confなどを適切に直しておきます。

swap領域がないととっても遅いので、swap file も用意します(たとえば、16MB)。

cd var
dd if=/dev/zero of=swapfile bs=1k count=16000
chmod 600 swapfile

共有できるディレクトリできないディレクトリ

おおまかにわけると、/usr, /usr/local, /homeは共有でき、/, /varは 共有できません。またswapファイルも別にする必要があります。

同一アーキテクチャ(i386)

/のうち共有できるディレクトリは、 /, /bin, /dev, /lkm, /proc, /root, /sbin, /stand と /usrなどのマウントポイント です。ただし /kernel は共有できるように工夫する必要があります。

/のうち共有できないのは、 /etc, /tmp, /var です。

/varのうち共有できるディレクトリは、 /var/db/pkg です。

ディスクレスクライアント間でほぼ同じ設定で動かすことを考えます。 /etcのうち問題になりそうなのは、 rc.conf, fstab, XF86Config です。fstabは、/は再マウントされないようなので、共有したくない /varが問題です。

rc.confはhostname, ifconfigが問題になりますが、hostnameは BOOTPで設定されているので、rc.confを見ないようです。 ifconfigは、rc.confで記述しないのが一つの手です。2つ目のインターフェース がある場合には問題になります。 keyboardの配列やマウスの接続先も問題になりそうです。 そこで、rc.confの最後に、

if [ "`hostname -s`" ] ; then
	if [ -f "/etc/rc.conf.`hostname -s`" ]; then
		. /etc/rc.conf.`hostname -s`
	fi
fi
を追加して、/etc/rc.conf.hostnameを使えるようにしました。これで rc.confは共通の設定(ディスクのついているサーバ用)、 ディスクレスクライアント1用の設定は rc.conf.client1 で上書きと することが出来ます。

NFS上のswapは元々の/etc/rcの順序(NFS mountする前にswaponする)では、 /varにおけません。そこで、/etc/rcに

--- rc.ORG      Tue Oct 21 23:21:08 1997
+++ rc  Mon Mar 22 17:43:14 1999
@@ -122,7 +122,16 @@
        network_pass1
 fi
 
+mount 10.93.63.51:/disk2/diskless/`hostname -s`-var /var
+mount 10.93.63.51:/disk2/diskless/`hostname -s`-tmp /tmp
+
 mount -a -t nfs
+
+# Add additional swapfile, if configured.
+if [ "x$nfsswapfile" != "xNO" -a -w "$nfsswapfile" -a -b /dev/vn0b ]; then
+       echo "Adding $nfsswapfile as additional swap."
+       vnconfig /dev/vn0b $nfsswapfile && swapon /dev/vn0b
+fi
 
 # Whack the pty perms back into shape.
 chmod 666 /dev/tty[pqrsPQRS]*
という変更を加えました(ディスクのついたマシンのことは考えていません)。 これで、/varに swapファイルを置くことが出来ます。 NFS上のswapファイルの位置は、nfsswapfileに書くことにしています。

XF86Configは、/etc/XF86Configではなく、 /usr/X11R6/lib/X11/XF86Config.hostname にすればマシン毎に分けられます。

/usrのうち共有できないのは、/usr/X11R6/bin/X, /usr/local/etc/rc.d です。どちらも、すべてのクライアントで同一とする(できる)なら そのままで大丈夫です。