直接アクセスできないネットワークにあるNFSサーバをNFSでマウントすることはできないか試行錯誤してみた。
普通にCentOS7やSolaris11からやってみたところ、NFSマウントした領域のNFS exportでの公開はnfsd側から「Cannot export /mnt, possibly unsupported filesystem or fsid= required」とか、「Invalid filesystem」とか言われて設定できない。
これはuser-spaceで動作するnfsdを使えば回避できるんじゃないかと探してみた結果、unfs3というものを発見。ソースコードは https://github.com/unfs3/unfs3
Linux,FreeBSD,Solaris,AIX,Irix,MacOSXで動く以外に、Windows上でも制限ありで動作するとのこと。
Windows上で動かした場合は、unfsdが使用するWindowsユーザを1つ割り当てる形になるので、NFS経由のアクセスは全てそのWindowsユーザがアクセスしている、という扱いになるようだ。
あと、このunfs3はNFS ver3のみ使え、NFS v4やNFS v2でのアクセスには対応していない。また、NFS v3でもREADDIRPLUS(属性付きディレクトリの読み取り)周りは実装していないとのこと。
READDIRPLUSはOracle/Solarisのドキュメントによればlsコマンドなどでディレクトリ内のファイル一覧を表示させる動作を高速化するためのものなので、まぁ、なくてもなんとかなる感じのもの。
属性付きディレクトリの読み取り
NFS バージョン 3 では、READDIRPLUS と呼ばれる操作があります。たとえば、ls や ls -l などの、大部分の READDIR が READDIRPLUS コールとして発行されます。バージョン 3 で ls -l コマンドを実行すると、ディレクトリ内の名前リストと共に、ファイルハンドルと属性が返されます。バージョン 2 では、名前が最初に返され、ファイルハンドルと属性を取得するには、続いてサーバーを呼び出す必要があります。
バージョン 3 の READDIRPLUS 操作の利点は、ファイルごとに GETATTR 要求を送信する必要がないため時間が短縮され、ls と ls -l の速度が同程度になることです。
要件は満たせそうなので、とりあえずテスト用CentOS7環境でunfs3を動作させてみる。
準備
環境をインストール
# yum install git
# yum groupinstall "開発ツール"
コンパイル
まず、ソースコードの入手
$ git clone https://github.com/unfs3/unfs3.git
READMEにあるとおりbootstrap&configureを実行
$ cd unfs3/unfs3
$ ./bootstrap
$ ./configure
そしてmake
$ make
for i in Config ; do (cd $i && make all) || exit; done
make[1]: ディレクトリ `/root/unfs3/Config' に入ります
gcc -g -O2 -Wall -W -I.. -I. -I.. -c -o lex.yy.o lex.yy.c
gcc -g -O2 -Wall -W -I.. -I. -I.. -c -o y.tab.o y.tab.c
ar crs lib.a lex.yy.o y.tab.o
make[1]: ディレクトリ `/root/unfs3/Config' から出ます
gcc -g -O2 -Wall -W -D_GNU_SOURCE -I. -c -o afsgettimes.o afsgettimes.c
gcc -g -O2 -Wall -W -D_GNU_SOURCE -I. -c -o afssupport.o afssupport.c
gcc -g -O2 -Wall -W -D_GNU_SOURCE -I. -c -o attr.o attr.c
attr.c: 関数 ‘get_free_bad_dir_entry’ 内:
attr.c:550:5: エラー: ‘for’ ループ初期化宣言は C99 モード内でのみ許可されてい ます
for (int i = 0;i < BAD_DIR_CACHE_SIZE;i++) {
^
attr.c:550:5: 備考: オプション -std=c99 または -std=gnu99 をコードコンパイル時に使用してください
attr.c: 関数 ‘find_bad_dir_entry’ 内:
attr.c:573:5: エラー: ‘for’ ループ初期化宣言は C99 モード内でのみ許可されてい ます
for (int i = 0;i < BAD_DIR_CACHE_SIZE;i++) {
^
make: *** [attr.o] エラー 1
$
エラーとなってしまいます。
これはコンパイル時のオプションに「-std=c99」を指定するようにして解決
$ export CPPFLAGS="-std=c99";./configure
$ make
<略>
$
インストールと設定
普通にmake installすると/usr/local以下にインストールされます。
# make install
/usr/bin/install -c -d /usr/local/sbin
/usr/bin/install -c -d /usr/local/share/man/man7
/usr/bin/install -c -d /usr/local/share/man/man8
/usr/bin/install -c unfsd /usr/local/sbin/unfsd
/usr/bin/install -c -m 644 ./Extras/tags.7 /usr/local/share/man/man7/tags.7
/usr/bin/install -c -m 644 ./unfsd.8 /usr/local/share/man/man8/unfsd.8
#
NFSで公開するディレクトリの設定は、普通のnfsdと同じく /etc/exports ファイルを使用。「-e」オプションで別のファイルを指定することも可能です。
注意点としては、Linuxだとホスト名指定に「*」とnetgroupが使用できず、ログに「unfsd[20479]: syntax error in ‘/etc/exports’, exporting nothing」といった出力が出てしまうという点です。
「*」については「0.0.0.0/0」で代替できます。
/etc/exports ファイルを編集した場合、変更にはexportfsコマンドは使用できません。
unfsdに対してHUPシグナルを送ることで反映されます。(kill -HUP unfsdのPID)
unfsdの起動は「/usr/local/sbin/unfsd」の実行、停止はunfsdへのTERMシグナル送信(kill -TERM unfsdのPID)です。