chatty9p〜9Pプロトコルをのぞき見る

昨日はファイルサーバの雛形について書いたが,9Pプロトコルをハンドリングするライブラリlib9pを使ったので,実際にどんなメッセージがやり取りされているかわからなかった.そこで,今日はメッセージのやり取りについて具体的に見ていこうと思う.
lib9pは,やり取りされるメッセージを端末に出力するか制御するグローバル変数chatty9pを提供している.デフォルトは0だが,これを非0にすると,メッセージの内容が人間が読める形式で出力してくれるので,9Pプロトコルの勉強や,デバッグに便利である.
ramfsにならう形でmysrvに-Dオプションを追加しよう.Plan9では,コマンドラインオプションの解析用にARGBEGIN,ARGEND,ARGFといったマクロが用意されている.そこで,次のコードをmain関数の先頭に追加すればよい.

	ARGBEGIN {
	case 'D':
		chatty9p++;
		break;
	} ARGEND;

-Dオプションを付けて,mysrvを実行してみよう.postfdはpostmountsrvから呼ばれ,/srv/mysrvをcreateし,srvfdをpostしていることを示している.

% mysrv -D
postfd /srv/mysrv
postfd successful

9Pプロトコルの処理は,mountから始まる.mountでは,version,auth,attachというメッセージがやり取りされている.メッセージの先頭のTはクライアントからファイルサーバ(mysrv)へ,Rはファイルサーバからクライアントへメッセージが送られていることを示している.矢印の間の数字はファイル記述子infd,outfdである.メッセージの向きに着目すると,常にクライアントからのリクエストに対して,ファイルサーバがリプライを返していることがわかる.これは,すべてのメッセージに共通する決まりごとである.
version,authで9Pコネクションが確立する.attachはクライアントが指定したfidとファイルサーバのファイルツリーのルートを対応付けることを意味する.fidはクライアントが保持するファイル識別子で,readやwriteはfidに対してリクエストする.

% mount /srv/mysrv /n/mysrv
<-5- Tversion tag 65535 msize 8216 version '9P2000'
-5-> Rversion tag 65535 msize 8216 version '9P2000'
<-5- Tauth tag 5 afid 267 uname oraccha aname
-5-> Rerror tag 5 ename mysrv: authentication not required
<-5- Tattach tag 5 fid 267 afid -1 uname oraccha aname
-5-> Rattach tag 5 qid (0000000000000000 0 d)

catしてみる.walkとclunkが耳慣れないと思うが,walkはパス名の検索,clunkはfidの解放(closeに近い)を意味する.mysrvはTreadメッセージを受け取ると,myread関数を実行し,Rreadメッセージで結果を返している.

% cat /n/mysrv/data
<-5- Twalk tag 5 fid 267 newfid 268 nwname 1 0:data
-5-> Rwalk tag 5 nwqid 1 0:(0000000000000001 0 )
<-5- Topen tag 5 fid 268 mode 0
fid mode is 0x0
-5-> Ropen tag 5 qid (0000000000000001 0 ) iounit 0
<-5- Tread tag 5 fid 268 offset 0 count 8192
-5-> Rread tag 5 count 18 'home=/usr/oraccha
'
home=/usr/oraccha
<-5- Tread tag 5 fid 268 offset 18 count 8192
-5-> Rread tag 5 count 0 ''
<-5- Tclunk tag 5 fid 268
-5-> Rclunk tag 5

最後にunmount.

% unmount /n/mysrv
<-5- Tclunk tag 5 fid 267
-5-> Rclunk tag 5
% rm /srv/mysrv

NFSを知っている人なら,あぁ,やっていることはNFSのRPCと同じだなとわかるだろう.もちろん違う点もある.NFSはステートレスなプロトコルであるが,9Pはステートフルである.クライアントは状態を持っている.この状態はFid構造体として保持され,その識別子が前述のfidである.