read/writeの中身

続いて,read/writeの中身を埋めていこう.コードを解説する前に,一つおさらい.「プロセスグループ」にも書いたように,各ファイルにはQidというファイルサーバローカルで,ユニークな識別子が付けられている.以下のコードでは,このQidを利用して,ctlファイルとdataファイルの処理を区別している.Qidはゼロオリジンで,createfileごとにインクリメントされる.つまり,この例ではctlファイルのQidが0,dataファイルのQidが1となる*1

コード例として,ctlファイルに環境変数名を設定したら,dataファイルにその値がセットされるものを考えてみる.変更箇所であるmyread,mywrite関数を次に示す.readstr(2)で文字列をアプリに返している.readstr自体はrespondを呼ばないので,ちゃんと明示的にrespondを呼ぶ必要がある.

enum {
	Qctl,
	Qdata,
};

void 
myread(Req *r)
{
	int qid = (int)r->fid->qid.path;
	char data[1024], *e;

	switch (qid) {
	case Qctl:
		sprint(data, "env=%s\n", ename);
		readstr(r, data);
		break;
	case Qdata:
		e = getenv(ename);
		if (e) {
			sprint(data, "%s=%s\n", ename, e);
			readstr(r, data);
		}
		break;
	}
	respond(r, nil);
}

void 
mywrite(Req *r)
{
	int qid = (int)r->fid->qid.path;
	char data[1024];

	switch (qid) {
	case Qctl:
		memmove(data, r->ifcall.data, r->ifcall.count);
		data[r->ifcall.count] = '\0';
		strcpy(ename, data);
	}
	respond(r, nil);
}

次のような実行結果になる.なお,lsに-qオプションを付けると,Qidが表示される.

% mysrv
% mount /srv/mysrv /n/mysrv
% ls -q /n/mysrv
(00000000000000000 0 00) /n/mysrv/ctl
(00000000000000001 0 00) /n/mysrv/data
% cat /n/mysrv/ctl
home
% cat /n/mysrv/data
home=/usr/oraccha
% echo -n user > /n/mysrv/ctl
% cat /n/mysrv/data
user=oraccha

もっと具体的なコードとしてramfsが挙げられるかなと思ったけど,ramfsはpostmountsrvを使わず,自前でrforkして,イベントループを作っているみたい.なんでだろう? nntpfsやwebfs,wikifsはpostmountsrvを使っている.

*1:正確にはQidではなく,Qid.pathの値だけど,煩雑なのでこう書いた.pathと書くとパス名のように誤解するかもしれないが,64ビットの整数値である.