xref: /plan9/sys/src/cmd/iostats/statsrv.c (revision c93608cc76758b2be624199c6208a0f90bad298d)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #define Extern	extern
63e12c5d1SDavid du Colombier #include "statfs.h"
73e12c5d1SDavid du Colombier 
89a747e4fSDavid du Colombier char Ebadfid[]	= "Bad fid";
99a747e4fSDavid du Colombier char Enotdir[]	="Not a directory";
109a747e4fSDavid du Colombier char Edupfid[]	= "Fid already in use";
119a747e4fSDavid du Colombier char Eopen[]	= "Fid already opened";
129a747e4fSDavid du Colombier char Exmnt[]	= "Cannot .. past mount point";
139a747e4fSDavid du Colombier char Enoauth[]	= "iostats: Authentication failed";
149a747e4fSDavid du Colombier char Ebadver[]	= "Unrecognized 9P version";
153e12c5d1SDavid du Colombier 
169a747e4fSDavid du Colombier int
okfile(char * s,int mode)179a747e4fSDavid du Colombier okfile(char *s, int mode)
183e12c5d1SDavid du Colombier {
199a747e4fSDavid du Colombier 	if(strncmp(s, "/fd/", 3) == 0){
209a747e4fSDavid du Colombier 		/* 0, 1, and 2 we handle ourselves */
219a747e4fSDavid du Colombier 		if(s[4]=='/' || atoi(s+4) > 2)
229a747e4fSDavid du Colombier 			return 0;
239a747e4fSDavid du Colombier 		return 1;
249a747e4fSDavid du Colombier 	}
259a747e4fSDavid du Colombier 	if(strncmp(s, "/net/ssl", 8) == 0)
269a747e4fSDavid du Colombier 		return 0;
279a747e4fSDavid du Colombier 	if(strncmp(s, "/net/tls", 8) == 0)
289a747e4fSDavid du Colombier 		return 0;
299a747e4fSDavid du Colombier 	if(strncmp(s, "/srv/", 5) == 0 && ((mode&3) == OWRITE || (mode&3) == ORDWR))
309a747e4fSDavid du Colombier 		return 0;
319a747e4fSDavid du Colombier 	return 1;
323e12c5d1SDavid du Colombier }
333e12c5d1SDavid du Colombier 
343e12c5d1SDavid du Colombier void
update(Rpc * rpc,vlong t)35ab3dc52fSDavid du Colombier update(Rpc *rpc, vlong t)
36dc5a79c1SDavid du Colombier {
37ab3dc52fSDavid du Colombier 	vlong t2;
38dc5a79c1SDavid du Colombier 
39ab3dc52fSDavid du Colombier 	t2 = nsec();
40ab3dc52fSDavid du Colombier 	t = t2 - t;
41ab3dc52fSDavid du Colombier 	if(t < 0)
42dc5a79c1SDavid du Colombier 		t = 0;
43dc5a79c1SDavid du Colombier 
44dc5a79c1SDavid du Colombier 	rpc->time += t;
45ab3dc52fSDavid du Colombier 	if(t < rpc->lo)
46ab3dc52fSDavid du Colombier 		rpc->lo = t;
47ab3dc52fSDavid du Colombier 	if(t > rpc->hi)
48ab3dc52fSDavid du Colombier 		rpc->hi = t;
49dc5a79c1SDavid du Colombier }
50dc5a79c1SDavid du Colombier 
51dc5a79c1SDavid du Colombier void
Xversion(Fsrpc * r)529a747e4fSDavid du Colombier Xversion(Fsrpc *r)
533e12c5d1SDavid du Colombier {
543e12c5d1SDavid du Colombier 	Fcall thdr;
55ab3dc52fSDavid du Colombier 	vlong t;
563e12c5d1SDavid du Colombier 
57ab3dc52fSDavid du Colombier 	t = nsec();
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier 	if(r->work.msize > IOHDRSZ+Maxfdata)
609a747e4fSDavid du Colombier 		thdr.msize = IOHDRSZ+Maxfdata;
619a747e4fSDavid du Colombier 	else
629a747e4fSDavid du Colombier 		thdr.msize = r->work.msize;
639a747e4fSDavid du Colombier 	myiounit = thdr.msize - IOHDRSZ;
649a747e4fSDavid du Colombier 	if(strncmp(r->work.version, "9P2000", 6) != 0){
659a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadver);
669a747e4fSDavid du Colombier 		r->busy = 0;
679a747e4fSDavid du Colombier 		return;
689a747e4fSDavid du Colombier 	}
699a747e4fSDavid du Colombier 	thdr.version = "9P2000";
709a747e4fSDavid du Colombier 	/* BUG: should clunk all fids */
713e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
723e12c5d1SDavid du Colombier 	r->busy = 0;
739a747e4fSDavid du Colombier 
74dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tversion], t);
759a747e4fSDavid du Colombier }
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier void
Xauth(Fsrpc * r)789a747e4fSDavid du Colombier Xauth(Fsrpc *r)
799a747e4fSDavid du Colombier {
809a747e4fSDavid du Colombier 	Fcall thdr;
81ab3dc52fSDavid du Colombier 	vlong t;
829a747e4fSDavid du Colombier 
83ab3dc52fSDavid du Colombier 	t = nsec();
849a747e4fSDavid du Colombier 
859a747e4fSDavid du Colombier 	reply(&r->work, &thdr, Enoauth);
869a747e4fSDavid du Colombier 	r->busy = 0;
879a747e4fSDavid du Colombier 
88dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tauth], t);
893e12c5d1SDavid du Colombier }
903e12c5d1SDavid du Colombier 
913e12c5d1SDavid du Colombier void
Xflush(Fsrpc * r)923e12c5d1SDavid du Colombier Xflush(Fsrpc *r)
933e12c5d1SDavid du Colombier {
943e12c5d1SDavid du Colombier 	Fsrpc *t, *e;
953e12c5d1SDavid du Colombier 	Fcall thdr;
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier 	e = &Workq[Nr_workbufs];
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier 	for(t = Workq; t < e; t++) {
1003e12c5d1SDavid du Colombier 		if(t->work.tag == r->work.oldtag) {
10174f16c81SDavid du Colombier 			DEBUG(2, "\tQ busy %d pid %p can %d\n", t->busy, t->pid, t->canint);
1023e12c5d1SDavid du Colombier 			if(t->busy && t->pid) {
1033e12c5d1SDavid du Colombier 				t->flushtag = r->work.tag;
1043e12c5d1SDavid du Colombier 				DEBUG(2, "\tset flushtag %d\n", r->work.tag);
1053e12c5d1SDavid du Colombier 				if(t->canint)
106219b2ee8SDavid du Colombier 					postnote(PNPROC, t->pid, "flush");
1073e12c5d1SDavid du Colombier 				r->busy = 0;
1083e12c5d1SDavid du Colombier 				return;
1093e12c5d1SDavid du Colombier 			}
1103e12c5d1SDavid du Colombier 		}
1113e12c5d1SDavid du Colombier 	}
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
1143e12c5d1SDavid du Colombier 	DEBUG(2, "\tflush reply\n");
1153e12c5d1SDavid du Colombier 	r->busy = 0;
1163e12c5d1SDavid du Colombier }
1173e12c5d1SDavid du Colombier 
1183e12c5d1SDavid du Colombier void
Xattach(Fsrpc * r)1193e12c5d1SDavid du Colombier Xattach(Fsrpc *r)
1203e12c5d1SDavid du Colombier {
1213e12c5d1SDavid du Colombier 	Fcall thdr;
1223e12c5d1SDavid du Colombier 	Fid *f;
123ab3dc52fSDavid du Colombier 	vlong t;
1243e12c5d1SDavid du Colombier 
125ab3dc52fSDavid du Colombier 	t = nsec();
1263e12c5d1SDavid du Colombier 
1273e12c5d1SDavid du Colombier 	f = newfid(r->work.fid);
1283e12c5d1SDavid du Colombier 	if(f == 0) {
1299a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
1303e12c5d1SDavid du Colombier 		r->busy = 0;
1313e12c5d1SDavid du Colombier 		return;
1323e12c5d1SDavid du Colombier 	}
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier 	f->f = root;
1353e12c5d1SDavid du Colombier 	thdr.qid = f->f->qid;
1363e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
1373e12c5d1SDavid du Colombier 	r->busy = 0;
1383e12c5d1SDavid du Colombier 
139dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tattach], t);
1403e12c5d1SDavid du Colombier }
1413e12c5d1SDavid du Colombier 
1423e12c5d1SDavid du Colombier void
Xwalk(Fsrpc * r)1439a747e4fSDavid du Colombier Xwalk(Fsrpc *r)
1443e12c5d1SDavid du Colombier {
1459a747e4fSDavid du Colombier 	char errbuf[ERRMAX], *err;
1463e12c5d1SDavid du Colombier 	Fcall thdr;
1473e12c5d1SDavid du Colombier 	Fid *f, *n;
1489a747e4fSDavid du Colombier 	File *nf;
149ab3dc52fSDavid du Colombier 	vlong t;
1509a747e4fSDavid du Colombier 	int i;
1513e12c5d1SDavid du Colombier 
152ab3dc52fSDavid du Colombier 	t = nsec();
1533e12c5d1SDavid du Colombier 
1543e12c5d1SDavid du Colombier 	f = getfid(r->work.fid);
1553e12c5d1SDavid du Colombier 	if(f == 0) {
1569a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
1573e12c5d1SDavid du Colombier 		r->busy = 0;
1583e12c5d1SDavid du Colombier 		return;
1593e12c5d1SDavid du Colombier 	}
1609a747e4fSDavid du Colombier 	n = nil;
1619a747e4fSDavid du Colombier 	if(r->work.newfid != r->work.fid){
1623e12c5d1SDavid du Colombier 		n = newfid(r->work.newfid);
1633e12c5d1SDavid du Colombier 		if(n == 0) {
1649a747e4fSDavid du Colombier 			reply(&r->work, &thdr, Edupfid);
1653e12c5d1SDavid du Colombier 			r->busy = 0;
1663e12c5d1SDavid du Colombier 			return;
1673e12c5d1SDavid du Colombier 		}
1683e12c5d1SDavid du Colombier 		n->f = f->f;
1699a747e4fSDavid du Colombier 		f = n;	/* walk new guy */
1703e12c5d1SDavid du Colombier 	}
1713e12c5d1SDavid du Colombier 
1729a747e4fSDavid du Colombier 	thdr.nwqid = 0;
1739a747e4fSDavid du Colombier 	err = nil;
1749a747e4fSDavid du Colombier 	for(i=0; i<r->work.nwname; i++){
1759a747e4fSDavid du Colombier 		if(i >= MAXWELEM)
1769a747e4fSDavid du Colombier 			break;
1779a747e4fSDavid du Colombier 		if(strcmp(r->work.wname[i], "..") == 0) {
1783e12c5d1SDavid du Colombier 			if(f->f->parent == 0) {
1799a747e4fSDavid du Colombier 				err = Exmnt;
1809a747e4fSDavid du Colombier 				break;
1813e12c5d1SDavid du Colombier 			}
1823e12c5d1SDavid du Colombier 			f->f = f->f->parent;
1839a747e4fSDavid du Colombier 			thdr.wqid[thdr.nwqid++] = f->f->qid;
1849a747e4fSDavid du Colombier 			continue;
1853e12c5d1SDavid du Colombier 		}
1863e12c5d1SDavid du Colombier 
1879a747e4fSDavid du Colombier 		nf = file(f->f, r->work.wname[i]);
1883e12c5d1SDavid du Colombier 		if(nf == 0) {
1899a747e4fSDavid du Colombier 			errstr(errbuf, sizeof errbuf);
1909a747e4fSDavid du Colombier 			err = errbuf;
1919a747e4fSDavid du Colombier 			break;
1923e12c5d1SDavid du Colombier 		}
1933e12c5d1SDavid du Colombier 
1943e12c5d1SDavid du Colombier 		f->f = nf;
1959a747e4fSDavid du Colombier 		thdr.wqid[thdr.nwqid++] = nf->qid;
1969a747e4fSDavid du Colombier 		continue;
1979a747e4fSDavid du Colombier 	}
1989a747e4fSDavid du Colombier 
1999a747e4fSDavid du Colombier 	if(err == nil && thdr.nwqid == 0 && r->work.nwname > 0)
2009a747e4fSDavid du Colombier 		err = "file does not exist";
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 	if(n != nil && (err != 0 || thdr.nwqid < r->work.nwname)){
2039a747e4fSDavid du Colombier 		/* clunk the new fid, which is the one we walked */
2049a747e4fSDavid du Colombier 		freefid(n->nr);
2059a747e4fSDavid du Colombier 	}
2069a747e4fSDavid du Colombier 
2079a747e4fSDavid du Colombier 	if(thdr.nwqid > 0)
2089a747e4fSDavid du Colombier 		err = nil;
2099a747e4fSDavid du Colombier 	reply(&r->work, &thdr, err);
2103e12c5d1SDavid du Colombier 	r->busy = 0;
2113e12c5d1SDavid du Colombier 
212dc5a79c1SDavid du Colombier 	update(&stats->rpc[Twalk], t);
2133e12c5d1SDavid du Colombier }
2143e12c5d1SDavid du Colombier 
2153e12c5d1SDavid du Colombier void
Xclunk(Fsrpc * r)2163e12c5d1SDavid du Colombier Xclunk(Fsrpc *r)
2173e12c5d1SDavid du Colombier {
2183e12c5d1SDavid du Colombier 	Fcall thdr;
2193e12c5d1SDavid du Colombier 	Fid *f;
220ab3dc52fSDavid du Colombier 	vlong t;
2213e12c5d1SDavid du Colombier 	int fid;
2223e12c5d1SDavid du Colombier 
223ab3dc52fSDavid du Colombier 	t = nsec();
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier 	f = getfid(r->work.fid);
2263e12c5d1SDavid du Colombier 	if(f == 0) {
2279a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
2283e12c5d1SDavid du Colombier 		r->busy = 0;
2293e12c5d1SDavid du Colombier 		return;
2303e12c5d1SDavid du Colombier 	}
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier 	if(f->fid >= 0)
2333e12c5d1SDavid du Colombier 		close(f->fid);
2343e12c5d1SDavid du Colombier 
2353e12c5d1SDavid du Colombier 	fid = r->work.fid;
2363e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
2373e12c5d1SDavid du Colombier 	r->busy = 0;
2383e12c5d1SDavid du Colombier 
239dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tclunk], t);
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	if(f->nread || f->nwrite)
2423e12c5d1SDavid du Colombier 		fidreport(f);
2433e12c5d1SDavid du Colombier 
2443e12c5d1SDavid du Colombier 	freefid(fid);
2453e12c5d1SDavid du Colombier }
2463e12c5d1SDavid du Colombier 
2473e12c5d1SDavid du Colombier void
Xstat(Fsrpc * r)2483e12c5d1SDavid du Colombier Xstat(Fsrpc *r)
2493e12c5d1SDavid du Colombier {
2509a747e4fSDavid du Colombier 	char err[ERRMAX], path[128];
2519a747e4fSDavid du Colombier 	uchar statbuf[STATMAX];
2523e12c5d1SDavid du Colombier 	Fcall thdr;
2533e12c5d1SDavid du Colombier 	Fid *f;
2543e12c5d1SDavid du Colombier 	int s;
255ab3dc52fSDavid du Colombier 	vlong t;
2563e12c5d1SDavid du Colombier 
257ab3dc52fSDavid du Colombier 	t = nsec();
2583e12c5d1SDavid du Colombier 
2593e12c5d1SDavid du Colombier 	f = getfid(r->work.fid);
2603e12c5d1SDavid du Colombier 	if(f == 0) {
2619a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
2623e12c5d1SDavid du Colombier 		r->busy = 0;
2633e12c5d1SDavid du Colombier 		return;
2643e12c5d1SDavid du Colombier 	}
2653e12c5d1SDavid du Colombier 	makepath(path, f->f, "");
2669a747e4fSDavid du Colombier 	if(!okfile(path, -1)){
2679a747e4fSDavid du Colombier 		snprint(err, sizeof err, "iostats: can't simulate %s", path);
2683e12c5d1SDavid du Colombier 		reply(&r->work, &thdr, err);
2693e12c5d1SDavid du Colombier 		r->busy = 0;
2703e12c5d1SDavid du Colombier 		return;
2713e12c5d1SDavid du Colombier 	}
2729a747e4fSDavid du Colombier 
2739a747e4fSDavid du Colombier 	if(f->fid >= 0)
2749a747e4fSDavid du Colombier 		s = fstat(f->fid, statbuf, sizeof statbuf);
2759a747e4fSDavid du Colombier 	else
2769a747e4fSDavid du Colombier 		s = stat(path, statbuf, sizeof statbuf);
2779a747e4fSDavid du Colombier 
2789a747e4fSDavid du Colombier 	if(s < 0) {
2799a747e4fSDavid du Colombier 		errstr(err, sizeof err);
2809a747e4fSDavid du Colombier 		reply(&r->work, &thdr, err);
2819a747e4fSDavid du Colombier 		r->busy = 0;
2829a747e4fSDavid du Colombier 		return;
2839a747e4fSDavid du Colombier 	}
2849a747e4fSDavid du Colombier 	thdr.stat = statbuf;
2859a747e4fSDavid du Colombier 	thdr.nstat = s;
2863e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
2873e12c5d1SDavid du Colombier 	r->busy = 0;
2883e12c5d1SDavid du Colombier 
289dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tstat], t);
2903e12c5d1SDavid du Colombier }
2913e12c5d1SDavid du Colombier 
2923e12c5d1SDavid du Colombier void
Xcreate(Fsrpc * r)2933e12c5d1SDavid du Colombier Xcreate(Fsrpc *r)
2943e12c5d1SDavid du Colombier {
2959a747e4fSDavid du Colombier 	char err[ERRMAX], path[128];
2963e12c5d1SDavid du Colombier 	Fcall thdr;
2973e12c5d1SDavid du Colombier 	Fid *f;
2983e12c5d1SDavid du Colombier 	File *nf;
299ab3dc52fSDavid du Colombier 	vlong t;
3003e12c5d1SDavid du Colombier 
301ab3dc52fSDavid du Colombier 	t = nsec();
3023e12c5d1SDavid du Colombier 
3033e12c5d1SDavid du Colombier 	f = getfid(r->work.fid);
3043e12c5d1SDavid du Colombier 	if(f == 0) {
3059a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
3063e12c5d1SDavid du Colombier 		r->busy = 0;
3073e12c5d1SDavid du Colombier 		return;
3083e12c5d1SDavid du Colombier 	}
3093e12c5d1SDavid du Colombier 
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier 	makepath(path, f->f, r->work.name);
3123e12c5d1SDavid du Colombier 	f->fid = create(path, r->work.mode, r->work.perm);
3133e12c5d1SDavid du Colombier 	if(f->fid < 0) {
3149a747e4fSDavid du Colombier 		errstr(err, sizeof err);
3153e12c5d1SDavid du Colombier 		reply(&r->work, &thdr, err);
3163e12c5d1SDavid du Colombier 		r->busy = 0;
3173e12c5d1SDavid du Colombier 		return;
3183e12c5d1SDavid du Colombier 	}
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	nf = file(f->f, r->work.name);
3213e12c5d1SDavid du Colombier 	if(nf == 0) {
3229a747e4fSDavid du Colombier 		errstr(err, sizeof err);
3233e12c5d1SDavid du Colombier 		reply(&r->work, &thdr, err);
3243e12c5d1SDavid du Colombier 		r->busy = 0;
3253e12c5d1SDavid du Colombier 		return;
3263e12c5d1SDavid du Colombier 	}
3273e12c5d1SDavid du Colombier 
3283e12c5d1SDavid du Colombier 	f->mode = r->work.mode;
3293e12c5d1SDavid du Colombier 	f->f = nf;
3309a747e4fSDavid du Colombier 	thdr.iounit = myiounit;
3313e12c5d1SDavid du Colombier 	thdr.qid = f->f->qid;
3323e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
3333e12c5d1SDavid du Colombier 	r->busy = 0;
3343e12c5d1SDavid du Colombier 
335dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tcreate], t);
3363e12c5d1SDavid du Colombier }
3373e12c5d1SDavid du Colombier 
3383e12c5d1SDavid du Colombier 
3393e12c5d1SDavid du Colombier void
Xremove(Fsrpc * r)3403e12c5d1SDavid du Colombier Xremove(Fsrpc *r)
3413e12c5d1SDavid du Colombier {
3429a747e4fSDavid du Colombier 	char err[ERRMAX], path[128];
3433e12c5d1SDavid du Colombier 	Fcall thdr;
3443e12c5d1SDavid du Colombier 	Fid *f;
345ab3dc52fSDavid du Colombier 	vlong t;
3463e12c5d1SDavid du Colombier 
347ab3dc52fSDavid du Colombier 	t = nsec();
3483e12c5d1SDavid du Colombier 
3493e12c5d1SDavid du Colombier 	f = getfid(r->work.fid);
3503e12c5d1SDavid du Colombier 	if(f == 0) {
3519a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
3523e12c5d1SDavid du Colombier 		r->busy = 0;
3533e12c5d1SDavid du Colombier 		return;
3543e12c5d1SDavid du Colombier 	}
3553e12c5d1SDavid du Colombier 
3563e12c5d1SDavid du Colombier 	makepath(path, f->f, "");
3573e12c5d1SDavid du Colombier 	DEBUG(2, "\tremove: %s\n", path);
3583e12c5d1SDavid du Colombier 	if(remove(path) < 0) {
3599a747e4fSDavid du Colombier 		errstr(err, sizeof err);
3603e12c5d1SDavid du Colombier 		reply(&r->work, &thdr, err);
361219b2ee8SDavid du Colombier 		freefid(r->work.fid);
3623e12c5d1SDavid du Colombier 		r->busy = 0;
3633e12c5d1SDavid du Colombier 		return;
3643e12c5d1SDavid du Colombier 	}
3653e12c5d1SDavid du Colombier 
3667dd7cddfSDavid du Colombier 	f->f->inval = 1;
3673e12c5d1SDavid du Colombier 	if(f->fid >= 0)
3683e12c5d1SDavid du Colombier 		close(f->fid);
3693e12c5d1SDavid du Colombier 	freefid(r->work.fid);
3703e12c5d1SDavid du Colombier 
3713e12c5d1SDavid du Colombier 	reply(&r->work, &thdr, 0);
3723e12c5d1SDavid du Colombier 	r->busy = 0;
3733e12c5d1SDavid du Colombier 
374dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tremove], t);
3753e12c5d1SDavid du Colombier }
3763e12c5d1SDavid du Colombier 
3773e12c5d1SDavid du Colombier void
Xwstat(Fsrpc * r)3783e12c5d1SDavid du Colombier Xwstat(Fsrpc *r)
3793e12c5d1SDavid du Colombier {
3809a747e4fSDavid du Colombier 	char err[ERRMAX], path[128];
3813e12c5d1SDavid du Colombier 	Fcall thdr;
3823e12c5d1SDavid du Colombier 	Fid *f;
3833e12c5d1SDavid du Colombier 	int s;
384ab3dc52fSDavid du Colombier 	vlong t;
3853e12c5d1SDavid du Colombier 
386ab3dc52fSDavid du Colombier 	t = nsec();
3873e12c5d1SDavid du Colombier 
3883e12c5d1SDavid du Colombier 	f = getfid(r->work.fid);
3893e12c5d1SDavid du Colombier 	if(f == 0) {
3909a747e4fSDavid du Colombier 		reply(&r->work, &thdr, Ebadfid);
3913e12c5d1SDavid du Colombier 		r->busy = 0;
3923e12c5d1SDavid du Colombier 		return;
3933e12c5d1SDavid du Colombier 	}
3943e12c5d1SDavid du Colombier 	if(f->fid >= 0)
3959a747e4fSDavid du Colombier 		s = fwstat(f->fid, r->work.stat, r->work.nstat);
3963e12c5d1SDavid du Colombier 	else {
3973e12c5d1SDavid du Colombier 		makepath(path, f->f, "");
3989a747e4fSDavid du Colombier 		s = wstat(path, r->work.stat, r->work.nstat);
3993e12c5d1SDavid du Colombier 	}
4003e12c5d1SDavid du Colombier 	if(s < 0) {
4019a747e4fSDavid du Colombier 		errstr(err, sizeof err);
4023e12c5d1SDavid du Colombier 		reply(&r->work, &thdr, err);
4033e12c5d1SDavid du Colombier 	}
4043e12c5d1SDavid du Colombier 	else
4053e12c5d1SDavid du Colombier 		reply(&r->work, &thdr, 0);
4063e12c5d1SDavid du Colombier 
4073e12c5d1SDavid du Colombier 	r->busy = 0;
408dc5a79c1SDavid du Colombier 	update(&stats->rpc[Twstat], t);
4093e12c5d1SDavid du Colombier }
4103e12c5d1SDavid du Colombier 
4113e12c5d1SDavid du Colombier void
slave(Fsrpc * f)4123e12c5d1SDavid du Colombier slave(Fsrpc *f)
4133e12c5d1SDavid du Colombier {
414*c93608ccSDavid du Colombier 	int r;
4153e12c5d1SDavid du Colombier 	Proc *p;
41674f16c81SDavid du Colombier 	uintptr pid;
4173e12c5d1SDavid du Colombier 	static int nproc;
4183e12c5d1SDavid du Colombier 
4193e12c5d1SDavid du Colombier 	for(;;) {
4203e12c5d1SDavid du Colombier 		for(p = Proclist; p; p = p->next) {
4213e12c5d1SDavid du Colombier 			if(p->busy == 0) {
4223e12c5d1SDavid du Colombier 				f->pid = p->pid;
4233e12c5d1SDavid du Colombier 				p->busy = 1;
42474f16c81SDavid du Colombier 				pid = (uintptr)rendezvous((void*)p->pid, f);
4253e12c5d1SDavid du Colombier 				if(pid != p->pid)
4263e12c5d1SDavid du Colombier 					fatal("rendezvous sync fail");
4273e12c5d1SDavid du Colombier 				return;
4283e12c5d1SDavid du Colombier 			}
4293e12c5d1SDavid du Colombier 		}
4303e12c5d1SDavid du Colombier 
4313e12c5d1SDavid du Colombier 		if(++nproc > MAXPROC)
4323e12c5d1SDavid du Colombier 			fatal("too many procs");
4333e12c5d1SDavid du Colombier 
434*c93608ccSDavid du Colombier 		r = rfork(RFPROC|RFMEM);
435*c93608ccSDavid du Colombier 		if(r < 0)
4363e12c5d1SDavid du Colombier 			fatal("rfork");
4373e12c5d1SDavid du Colombier 
438*c93608ccSDavid du Colombier 		if(r == 0)
4393e12c5d1SDavid du Colombier 			blockingslave();
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 		p = malloc(sizeof(Proc));
4423e12c5d1SDavid du Colombier 		if(p == 0)
4433e12c5d1SDavid du Colombier 			fatal("out of memory");
4443e12c5d1SDavid du Colombier 
4453e12c5d1SDavid du Colombier 		p->busy = 0;
446*c93608ccSDavid du Colombier 		p->pid = r;
4473e12c5d1SDavid du Colombier 		p->next = Proclist;
4483e12c5d1SDavid du Colombier 		Proclist = p;
4493e12c5d1SDavid du Colombier 
450*c93608ccSDavid du Colombier 		rendezvous((void*)p->pid, p);
4513e12c5d1SDavid du Colombier 	}
4523e12c5d1SDavid du Colombier }
4533e12c5d1SDavid du Colombier 
4543e12c5d1SDavid du Colombier void
blockingslave(void)4553e12c5d1SDavid du Colombier blockingslave(void)
4563e12c5d1SDavid du Colombier {
4573e12c5d1SDavid du Colombier 	Proc *m;
45874f16c81SDavid du Colombier 	uintptr pid;
4593e12c5d1SDavid du Colombier 	Fsrpc *p;
4603e12c5d1SDavid du Colombier 	Fcall thdr;
4613e12c5d1SDavid du Colombier 
4623e12c5d1SDavid du Colombier 	notify(flushaction);
4633e12c5d1SDavid du Colombier 
4643e12c5d1SDavid du Colombier 	pid = getpid();
4653e12c5d1SDavid du Colombier 
46674f16c81SDavid du Colombier 	m = rendezvous((void*)pid, 0);
4673e12c5d1SDavid du Colombier 
4683e12c5d1SDavid du Colombier 	for(;;) {
46974f16c81SDavid du Colombier 		p = rendezvous((void*)pid, (void*)pid);
47074f16c81SDavid du Colombier 		if(p == (void*)~0)			/* Interrupted */
4713e12c5d1SDavid du Colombier 			continue;
4723e12c5d1SDavid du Colombier 
47374f16c81SDavid du Colombier 		DEBUG(2, "\tslave: %p %F b %d p %p\n", pid, &p->work, p->busy, p->pid);
4743e12c5d1SDavid du Colombier 		if(p->flushtag != NOTAG)
4753e12c5d1SDavid du Colombier 			return;
4763e12c5d1SDavid du Colombier 
4773e12c5d1SDavid du Colombier 		switch(p->work.type) {
4783e12c5d1SDavid du Colombier 		case Tread:
4793e12c5d1SDavid du Colombier 			slaveread(p);
4803e12c5d1SDavid du Colombier 			break;
4813e12c5d1SDavid du Colombier 		case Twrite:
4823e12c5d1SDavid du Colombier 			slavewrite(p);
4833e12c5d1SDavid du Colombier 			break;
4843e12c5d1SDavid du Colombier 		case Topen:
4853e12c5d1SDavid du Colombier 			slaveopen(p);
4863e12c5d1SDavid du Colombier 			break;
4873e12c5d1SDavid du Colombier 		default:
4883e12c5d1SDavid du Colombier 			reply(&p->work, &thdr, "exportfs: slave type error");
4893e12c5d1SDavid du Colombier 		}
4903e12c5d1SDavid du Colombier 		if(p->flushtag != NOTAG) {
4913e12c5d1SDavid du Colombier 			p->work.type = Tflush;
4923e12c5d1SDavid du Colombier 			p->work.tag = p->flushtag;
4933e12c5d1SDavid du Colombier 			reply(&p->work, &thdr, 0);
4943e12c5d1SDavid du Colombier 		}
4953e12c5d1SDavid du Colombier 		p->busy = 0;
4963e12c5d1SDavid du Colombier 		m->busy = 0;
4973e12c5d1SDavid du Colombier 	}
4983e12c5d1SDavid du Colombier }
4993e12c5d1SDavid du Colombier 
5003e12c5d1SDavid du Colombier void
slaveopen(Fsrpc * p)5013e12c5d1SDavid du Colombier slaveopen(Fsrpc *p)
5023e12c5d1SDavid du Colombier {
5039a747e4fSDavid du Colombier 	char err[ERRMAX], path[128];
5043e12c5d1SDavid du Colombier 	Fcall *work, thdr;
5053e12c5d1SDavid du Colombier 	Fid *f;
506ab3dc52fSDavid du Colombier 	vlong t;
5073e12c5d1SDavid du Colombier 
5083e12c5d1SDavid du Colombier 	work = &p->work;
5093e12c5d1SDavid du Colombier 
510ab3dc52fSDavid du Colombier 	t = nsec();
5113e12c5d1SDavid du Colombier 
5123e12c5d1SDavid du Colombier 	f = getfid(work->fid);
5133e12c5d1SDavid du Colombier 	if(f == 0) {
5149a747e4fSDavid du Colombier 		reply(work, &thdr, Ebadfid);
5153e12c5d1SDavid du Colombier 		return;
5163e12c5d1SDavid du Colombier 	}
5173e12c5d1SDavid du Colombier 	if(f->fid >= 0) {
5183e12c5d1SDavid du Colombier 		close(f->fid);
5193e12c5d1SDavid du Colombier 		f->fid = -1;
5203e12c5d1SDavid du Colombier 	}
5213e12c5d1SDavid du Colombier 
5223e12c5d1SDavid du Colombier 	makepath(path, f->f, "");
5233e12c5d1SDavid du Colombier 	DEBUG(2, "\topen: %s %d\n", path, work->mode);
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier 	p->canint = 1;
5263e12c5d1SDavid du Colombier 	if(p->flushtag != NOTAG)
5273e12c5d1SDavid du Colombier 		return;
5289a747e4fSDavid du Colombier 
5299a747e4fSDavid du Colombier 	if(!okfile(path, work->mode)){
5309a747e4fSDavid du Colombier 		snprint(err, sizeof err, "iostats can't simulate %s", path);
5319a747e4fSDavid du Colombier 		reply(work, &thdr, err);
5329a747e4fSDavid du Colombier 		return;
5339a747e4fSDavid du Colombier 	}
5349a747e4fSDavid du Colombier 
5353e12c5d1SDavid du Colombier 	/* There is a race here I ignore because there are no locks */
5363e12c5d1SDavid du Colombier 	f->fid = open(path, work->mode);
5373e12c5d1SDavid du Colombier 	p->canint = 0;
5383e12c5d1SDavid du Colombier 	if(f->fid < 0) {
5399a747e4fSDavid du Colombier 		errstr(err, sizeof err);
5403e12c5d1SDavid du Colombier 		reply(work, &thdr, err);
5413e12c5d1SDavid du Colombier 		return;
5423e12c5d1SDavid du Colombier 	}
5433e12c5d1SDavid du Colombier 
5443e12c5d1SDavid du Colombier 	DEBUG(2, "\topen: fd %d\n", f->fid);
5453e12c5d1SDavid du Colombier 	f->mode = work->mode;
5469a747e4fSDavid du Colombier 	thdr.iounit = myiounit;
5473e12c5d1SDavid du Colombier 	thdr.qid = f->f->qid;
5483e12c5d1SDavid du Colombier 	reply(work, &thdr, 0);
5493e12c5d1SDavid du Colombier 
550dc5a79c1SDavid du Colombier 	update(&stats->rpc[Topen], t);
5513e12c5d1SDavid du Colombier }
5523e12c5d1SDavid du Colombier 
5533e12c5d1SDavid du Colombier void
slaveread(Fsrpc * p)5543e12c5d1SDavid du Colombier slaveread(Fsrpc *p)
5553e12c5d1SDavid du Colombier {
5569a747e4fSDavid du Colombier 	char data[Maxfdata], err[ERRMAX];
5573e12c5d1SDavid du Colombier 	Fcall *work, thdr;
5583e12c5d1SDavid du Colombier 	Fid *f;
5593e12c5d1SDavid du Colombier 	int n, r;
560ab3dc52fSDavid du Colombier 	vlong t;
5613e12c5d1SDavid du Colombier 
5623e12c5d1SDavid du Colombier 	work = &p->work;
5633e12c5d1SDavid du Colombier 
564ab3dc52fSDavid du Colombier 	t = nsec();
5653e12c5d1SDavid du Colombier 
5663e12c5d1SDavid du Colombier 	f = getfid(work->fid);
5673e12c5d1SDavid du Colombier 	if(f == 0) {
5689a747e4fSDavid du Colombier 		reply(work, &thdr, Ebadfid);
5693e12c5d1SDavid du Colombier 		return;
5703e12c5d1SDavid du Colombier 	}
5713e12c5d1SDavid du Colombier 
5729a747e4fSDavid du Colombier 	n = (work->count > Maxfdata) ? Maxfdata : work->count;
5733e12c5d1SDavid du Colombier 	p->canint = 1;
5743e12c5d1SDavid du Colombier 	if(p->flushtag != NOTAG)
5753e12c5d1SDavid du Colombier 		return;
5769a747e4fSDavid du Colombier 	/* can't just call pread, since directories must update the offset */
5779a747e4fSDavid du Colombier 	if(f->f->qid.type&QTDIR){
5789a747e4fSDavid du Colombier 		if(work->offset != f->offset){
5799a747e4fSDavid du Colombier 			if(work->offset != 0){
5809a747e4fSDavid du Colombier 				snprint(err, sizeof err, "can't seek in directory from %lld to %lld", f->offset, work->offset);
5819a747e4fSDavid du Colombier 				reply(work, &thdr, err);
5829a747e4fSDavid du Colombier 				return;
5839a747e4fSDavid du Colombier 			}
5849a747e4fSDavid du Colombier 			if(seek(f->fid, 0, 0) != 0){
5859a747e4fSDavid du Colombier 				errstr(err, sizeof err);
5869a747e4fSDavid du Colombier 				reply(work, &thdr, err);
5879a747e4fSDavid du Colombier 				return;
5889a747e4fSDavid du Colombier 			}
5899a747e4fSDavid du Colombier 			f->offset = 0;
5909a747e4fSDavid du Colombier 		}
5913e12c5d1SDavid du Colombier 		r = read(f->fid, data, n);
5929a747e4fSDavid du Colombier 		if(r > 0)
5939a747e4fSDavid du Colombier 			f->offset += r;
5949a747e4fSDavid du Colombier 	}else
5959a747e4fSDavid du Colombier 		r = pread(f->fid, data, n, work->offset);
5963e12c5d1SDavid du Colombier 	p->canint = 0;
5973e12c5d1SDavid du Colombier 	if(r < 0) {
5989a747e4fSDavid du Colombier 		errstr(err, sizeof err);
5993e12c5d1SDavid du Colombier 		reply(work, &thdr, err);
6003e12c5d1SDavid du Colombier 		return;
6013e12c5d1SDavid du Colombier 	}
6023e12c5d1SDavid du Colombier 
6033e12c5d1SDavid du Colombier 	DEBUG(2, "\tread: fd=%d %d bytes\n", f->fid, r);
6043e12c5d1SDavid du Colombier 
6053e12c5d1SDavid du Colombier 	thdr.data = data;
6063e12c5d1SDavid du Colombier 	thdr.count = r;
6073e12c5d1SDavid du Colombier 	stats->totread += r;
6083e12c5d1SDavid du Colombier 	f->nread++;
6093e12c5d1SDavid du Colombier 	f->bread += r;
6103e12c5d1SDavid du Colombier 	reply(work, &thdr, 0);
6113e12c5d1SDavid du Colombier 
612dc5a79c1SDavid du Colombier 	update(&stats->rpc[Tread], t);
6133e12c5d1SDavid du Colombier }
6143e12c5d1SDavid du Colombier 
6153e12c5d1SDavid du Colombier void
slavewrite(Fsrpc * p)6163e12c5d1SDavid du Colombier slavewrite(Fsrpc *p)
6173e12c5d1SDavid du Colombier {
6189a747e4fSDavid du Colombier 	char err[ERRMAX];
6193e12c5d1SDavid du Colombier 	Fcall *work, thdr;
6203e12c5d1SDavid du Colombier 	Fid *f;
6213e12c5d1SDavid du Colombier 	int n;
622ab3dc52fSDavid du Colombier 	vlong t;
6233e12c5d1SDavid du Colombier 
6243e12c5d1SDavid du Colombier 	work = &p->work;
6253e12c5d1SDavid du Colombier 
626ab3dc52fSDavid du Colombier 	t = nsec();
6273e12c5d1SDavid du Colombier 
6283e12c5d1SDavid du Colombier 	f = getfid(work->fid);
6293e12c5d1SDavid du Colombier 	if(f == 0) {
6309a747e4fSDavid du Colombier 		reply(work, &thdr, Ebadfid);
6313e12c5d1SDavid du Colombier 		return;
6323e12c5d1SDavid du Colombier 	}
6333e12c5d1SDavid du Colombier 
6349a747e4fSDavid du Colombier 	n = (work->count > Maxfdata) ? Maxfdata : work->count;
6353e12c5d1SDavid du Colombier 	p->canint = 1;
6363e12c5d1SDavid du Colombier 	if(p->flushtag != NOTAG)
6373e12c5d1SDavid du Colombier 		return;
6389a747e4fSDavid du Colombier 	n = pwrite(f->fid, work->data, n, work->offset);
6393e12c5d1SDavid du Colombier 	p->canint = 0;
6403e12c5d1SDavid du Colombier 	if(n < 0) {
6419a747e4fSDavid du Colombier 		errstr(err, sizeof err);
6423e12c5d1SDavid du Colombier 		reply(work, &thdr, err);
6433e12c5d1SDavid du Colombier 		return;
6443e12c5d1SDavid du Colombier 	}
6453e12c5d1SDavid du Colombier 
6463e12c5d1SDavid du Colombier 	DEBUG(2, "\twrite: %d bytes fd=%d\n", n, f->fid);
6473e12c5d1SDavid du Colombier 
6483e12c5d1SDavid du Colombier 	thdr.count = n;
6493e12c5d1SDavid du Colombier 	f->nwrite++;
6503e12c5d1SDavid du Colombier 	f->bwrite += n;
6513e12c5d1SDavid du Colombier 	stats->totwrite += n;
6523e12c5d1SDavid du Colombier 	reply(work, &thdr, 0);
6533e12c5d1SDavid du Colombier 
654dc5a79c1SDavid du Colombier 	update(&stats->rpc[Twrite], t);
6553e12c5d1SDavid du Colombier }
6563e12c5d1SDavid du Colombier 
6573e12c5d1SDavid du Colombier void
reopen(Fid * f)6583e12c5d1SDavid du Colombier reopen(Fid *f)
6593e12c5d1SDavid du Colombier {
6603e12c5d1SDavid du Colombier 	USED(f);
6613e12c5d1SDavid du Colombier 	fatal("reopen");
6623e12c5d1SDavid du Colombier }
6633e12c5d1SDavid du Colombier 
6643e12c5d1SDavid du Colombier void
flushaction(void * a,char * cause)6653e12c5d1SDavid du Colombier flushaction(void *a, char *cause)
6663e12c5d1SDavid du Colombier {
6673e12c5d1SDavid du Colombier 	USED(a);
6683e12c5d1SDavid du Colombier 	if(strncmp(cause, "kill", 4) == 0)
6693e12c5d1SDavid du Colombier 		noted(NDFLT);
6703e12c5d1SDavid du Colombier 
6713e12c5d1SDavid du Colombier 	noted(NCONT);
6723e12c5d1SDavid du Colombier }
673