xref: /plan9/sys/src/cmd/cfs/cfs.c (revision 7c70c028d2d46a27a61ae88e6df0eb0935d9da7a)
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 
63e12c5d1SDavid du Colombier #include "cformat.h"
73e12c5d1SDavid du Colombier #include "lru.h"
83e12c5d1SDavid du Colombier #include "bcache.h"
93e12c5d1SDavid du Colombier #include "disk.h"
103e12c5d1SDavid du Colombier #include "inode.h"
113e12c5d1SDavid du Colombier #include "file.h"
129a747e4fSDavid du Colombier #include "stats.h"
133e12c5d1SDavid du Colombier 
143e12c5d1SDavid du Colombier enum
153e12c5d1SDavid du Colombier {
167dd7cddfSDavid du Colombier 	Nfid=		10240,
173e12c5d1SDavid du Colombier };
183e12c5d1SDavid du Colombier 
199a747e4fSDavid du Colombier /* maximum length of a file */
209a747e4fSDavid du Colombier #define MAXLEN 0x7fffffffffffffffLL
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier typedef struct Mfile Mfile;
233e12c5d1SDavid du Colombier typedef struct Ram Ram;
243e12c5d1SDavid du Colombier typedef struct P9fs P9fs;
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier struct Mfile
273e12c5d1SDavid du Colombier {
283e12c5d1SDavid du Colombier 	Qid	qid;
293e12c5d1SDavid du Colombier 	char	busy;
303e12c5d1SDavid du Colombier };
313e12c5d1SDavid du Colombier 
323e12c5d1SDavid du Colombier Mfile	mfile[Nfid];
333e12c5d1SDavid du Colombier Icache	ic;
349a747e4fSDavid du Colombier int	debug, statson;
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier struct P9fs
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	int	fd[2];
393e12c5d1SDavid du Colombier 	Fcall	rhdr;
403e12c5d1SDavid du Colombier 	Fcall	thdr;
413e12c5d1SDavid du Colombier 	long	len;
423e12c5d1SDavid du Colombier 	char	*name;
433e12c5d1SDavid du Colombier };
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier P9fs	c;	/* client conversation */
463e12c5d1SDavid du Colombier P9fs	s;	/* server conversation */
473e12c5d1SDavid du Colombier 
489a747e4fSDavid du Colombier struct Cfsstat  cfsstat, cfsprev;
499a747e4fSDavid du Colombier char	statbuf[2048];
509a747e4fSDavid du Colombier int	statlen;
513e12c5d1SDavid du Colombier 
529a747e4fSDavid du Colombier #define	MAXFDATA	8192	/* i/o size for read/write */
539a747e4fSDavid du Colombier 
549a747e4fSDavid du Colombier int		messagesize = MAXFDATA+IOHDRSZ;
559a747e4fSDavid du Colombier 
569a747e4fSDavid du Colombier uchar	datasnd[MAXFDATA + IOHDRSZ];
579a747e4fSDavid du Colombier uchar	datarcv[MAXFDATA + IOHDRSZ];
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier Qid	rootqid;
609a747e4fSDavid du Colombier Qid	ctlqid = {0x5555555555555555LL, 0, 0};
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier void	rversion(void);
639a747e4fSDavid du Colombier void	rauth(Mfile*);
643e12c5d1SDavid du Colombier void	rflush(void);
653e12c5d1SDavid du Colombier void	rattach(Mfile*);
663e12c5d1SDavid du Colombier void	rwalk(Mfile*);
673e12c5d1SDavid du Colombier void	ropen(Mfile*);
683e12c5d1SDavid du Colombier void	rcreate(Mfile*);
693e12c5d1SDavid du Colombier void	rread(Mfile*);
703e12c5d1SDavid du Colombier void	rwrite(Mfile*);
713e12c5d1SDavid du Colombier void	rclunk(Mfile*);
723e12c5d1SDavid du Colombier void	rremove(Mfile*);
733e12c5d1SDavid du Colombier void	rstat(Mfile*);
743e12c5d1SDavid du Colombier void	rwstat(Mfile*);
759a747e4fSDavid du Colombier void	error(char*, ...);
763e12c5d1SDavid du Colombier void	warning(char*);
773e12c5d1SDavid du Colombier void	mountinit(char*, char*);
783e12c5d1SDavid du Colombier void	io(void);
793e12c5d1SDavid du Colombier void	sendreply(char*);
803e12c5d1SDavid du Colombier void	sendmsg(P9fs*, Fcall*);
813e12c5d1SDavid du Colombier void	rcvmsg(P9fs*, Fcall*);
823e12c5d1SDavid du Colombier int	delegate(void);
833e12c5d1SDavid du Colombier int	askserver(void);
84*7c70c028SDavid du Colombier void	cachesetup(int, char*, char*);
859a747e4fSDavid du Colombier int	ctltest(Mfile*);
869a747e4fSDavid du Colombier void	genstats(void);
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier char *mname[]={
899a747e4fSDavid du Colombier 	[Tversion]		"Tversion",
909a747e4fSDavid du Colombier 	[Tauth]	"Tauth",
913e12c5d1SDavid du Colombier 	[Tflush]	"Tflush",
923e12c5d1SDavid du Colombier 	[Tattach]	"Tattach",
933e12c5d1SDavid du Colombier 	[Twalk]		"Twalk",
943e12c5d1SDavid du Colombier 	[Topen]		"Topen",
953e12c5d1SDavid du Colombier 	[Tcreate]	"Tcreate",
963e12c5d1SDavid du Colombier 	[Tclunk]	"Tclunk",
973e12c5d1SDavid du Colombier 	[Tread]		"Tread",
983e12c5d1SDavid du Colombier 	[Twrite]	"Twrite",
993e12c5d1SDavid du Colombier 	[Tremove]	"Tremove",
1003e12c5d1SDavid du Colombier 	[Tstat]		"Tstat",
1013e12c5d1SDavid du Colombier 	[Twstat]	"Twstat",
1029a747e4fSDavid du Colombier 	[Rversion]	"Rversion",
1039a747e4fSDavid du Colombier 	[Rauth]	"Rauth",
1043e12c5d1SDavid du Colombier 	[Rerror]	"Rerror",
1053e12c5d1SDavid du Colombier 	[Rflush]	"Rflush",
1063e12c5d1SDavid du Colombier 	[Rattach]	"Rattach",
1073e12c5d1SDavid du Colombier 	[Rwalk]		"Rwalk",
1083e12c5d1SDavid du Colombier 	[Ropen]		"Ropen",
1093e12c5d1SDavid du Colombier 	[Rcreate]	"Rcreate",
1103e12c5d1SDavid du Colombier 	[Rclunk]	"Rclunk",
1113e12c5d1SDavid du Colombier 	[Rread]		"Rread",
1123e12c5d1SDavid du Colombier 	[Rwrite]	"Rwrite",
1133e12c5d1SDavid du Colombier 	[Rremove]	"Rremove",
1143e12c5d1SDavid du Colombier 	[Rstat]		"Rstat",
1153e12c5d1SDavid du Colombier 	[Rwstat]	"Rwstat",
1163e12c5d1SDavid du Colombier 			0,
1173e12c5d1SDavid du Colombier };
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier void
1203e12c5d1SDavid du Colombier usage(void)
1213e12c5d1SDavid du Colombier {
122*7c70c028SDavid du Colombier 	fprint(2, "usage:\tcfs -s [-krd] [-f partition]\n");
123*7c70c028SDavid du Colombier 	fprint(2, "\tcfs [-krd] [-f partition] [-a netaddr] [mt-pt]\n");
1249a747e4fSDavid du Colombier 	exits("usage");
1253e12c5d1SDavid du Colombier }
1263e12c5d1SDavid du Colombier 
1273e12c5d1SDavid du Colombier void
1283e12c5d1SDavid du Colombier main(int argc, char *argv[])
1293e12c5d1SDavid du Colombier {
1303e12c5d1SDavid du Colombier 	int std;
1313e12c5d1SDavid du Colombier 	int format;
1323e12c5d1SDavid du Colombier 	char *part;
1333e12c5d1SDavid du Colombier 	char *server;
1343e12c5d1SDavid du Colombier 	char *mtpt;
1353e12c5d1SDavid du Colombier 
136*7c70c028SDavid du Colombier 	int chkid;
137*7c70c028SDavid du Colombier 	NetConnInfo * snci;
138*7c70c028SDavid du Colombier 
1393e12c5d1SDavid du Colombier 	std = 0;
1403e12c5d1SDavid du Colombier 	format = 0;
141*7c70c028SDavid du Colombier 	chkid = 1;
1427dd7cddfSDavid du Colombier 	part = "/dev/sdC0/cache";
143*7c70c028SDavid du Colombier 	server = "tcp!fs";
1443e12c5d1SDavid du Colombier 	mtpt = "/tmp";
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier 	ARGBEGIN{
1473e12c5d1SDavid du Colombier 	case 'a':
14807b9f4d0SDavid du Colombier 		server = EARGF(usage());
1493e12c5d1SDavid du Colombier 		break;
1509a747e4fSDavid du Colombier 	case 'S':
1519a747e4fSDavid du Colombier 		statson = 1;
1529a747e4fSDavid du Colombier 		break;
1533e12c5d1SDavid du Colombier 	case 's':
1543e12c5d1SDavid du Colombier 		std = 1;
1553e12c5d1SDavid du Colombier 		break;
1563e12c5d1SDavid du Colombier 	case 'r':
1573e12c5d1SDavid du Colombier 		format = 1;
1583e12c5d1SDavid du Colombier 		break;
1593e12c5d1SDavid du Colombier 	case 'f':
16007b9f4d0SDavid du Colombier 		part = EARGF(usage());
1613e12c5d1SDavid du Colombier 		break;
1623e12c5d1SDavid du Colombier 	case 'd':
1633e12c5d1SDavid du Colombier 		debug = 1;
1643e12c5d1SDavid du Colombier 		break;
165*7c70c028SDavid du Colombier 	case 'k':
166*7c70c028SDavid du Colombier 		chkid = 0;
167*7c70c028SDavid du Colombier 		break;
1683e12c5d1SDavid du Colombier 	default:
1693e12c5d1SDavid du Colombier 		usage();
1703e12c5d1SDavid du Colombier 	}ARGEND
1713e12c5d1SDavid du Colombier 	if(argc && *argv)
1723e12c5d1SDavid du Colombier 		mtpt = *argv;
1733e12c5d1SDavid du Colombier 
1747dd7cddfSDavid du Colombier 	if(debug)
1759a747e4fSDavid du Colombier 		fmtinstall('F', fcallfmt);
1767dd7cddfSDavid du Colombier 
1773e12c5d1SDavid du Colombier 	c.name = "client";
1783e12c5d1SDavid du Colombier 	s.name = "server";
1793e12c5d1SDavid du Colombier 	if(std){
1803e12c5d1SDavid du Colombier 		c.fd[0] = c.fd[1] = 1;
1813e12c5d1SDavid du Colombier 		s.fd[0] = s.fd[1] = 0;
1823e12c5d1SDavid du Colombier 	}else
1833e12c5d1SDavid du Colombier 		mountinit(server, mtpt);
1843e12c5d1SDavid du Colombier 
185*7c70c028SDavid du Colombier 	if(chkid){
186*7c70c028SDavid du Colombier 		if((snci = getnetconninfo(nil, s.fd[0])) == nil)
187*7c70c028SDavid du Colombier 			/* Failed to lookup information; format */
188*7c70c028SDavid du Colombier 			cachesetup(1, nil, part);
189*7c70c028SDavid du Colombier 		else
190*7c70c028SDavid du Colombier 			/* Do partition check */
191*7c70c028SDavid du Colombier 			cachesetup(0, snci->raddr, part);
192*7c70c028SDavid du Colombier 	}else
193*7c70c028SDavid du Colombier 		/* Obey -f w/o regard to cache vs. remote server */
194*7c70c028SDavid du Colombier 		cachesetup(format, nil, part);
195*7c70c028SDavid du Colombier 
1963e12c5d1SDavid du Colombier 	switch(fork()){
1973e12c5d1SDavid du Colombier 	case 0:
1983e12c5d1SDavid du Colombier 		io();
1993e12c5d1SDavid du Colombier 		exits("");
2003e12c5d1SDavid du Colombier 	case -1:
2013e12c5d1SDavid du Colombier 		error("fork");
2023e12c5d1SDavid du Colombier 	default:
2033e12c5d1SDavid du Colombier 		exits("");
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier void
208*7c70c028SDavid du Colombier cachesetup(int format, char *name, char *partition)
2093e12c5d1SDavid du Colombier {
2103e12c5d1SDavid du Colombier 	int f;
2113e12c5d1SDavid du Colombier 	int secsize;
2123e12c5d1SDavid du Colombier 	int inodes;
2133e12c5d1SDavid du Colombier 	int blocksize;
2143e12c5d1SDavid du Colombier 
2153e12c5d1SDavid du Colombier 	secsize = 512;
2163e12c5d1SDavid du Colombier 	inodes = 1024;
2173e12c5d1SDavid du Colombier 	blocksize = 4*1024;
2183e12c5d1SDavid du Colombier 
2193e12c5d1SDavid du Colombier 	f = open(partition, ORDWR);
2203e12c5d1SDavid du Colombier 	if(f < 0)
2213e12c5d1SDavid du Colombier 		error("opening partition");
2223e12c5d1SDavid du Colombier 
223*7c70c028SDavid du Colombier 	if(format || iinit(&ic, f, secsize, name) < 0){
224*7c70c028SDavid du Colombier 		/*
225*7c70c028SDavid du Colombier 		 * If we need to format and don't have a name, fall
226*7c70c028SDavid du Colombier 		 * back to our old behavior of using "bootes"
227*7c70c028SDavid du Colombier 		 */
228*7c70c028SDavid du Colombier 		name = (name == nil? "bootes": name);
229*7c70c028SDavid du Colombier 		if(iformat(&ic, f, inodes, name, blocksize, secsize) < 0)
2303e12c5d1SDavid du Colombier 			error("formatting failed");
2313e12c5d1SDavid du Colombier 	}
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier 
2343e12c5d1SDavid du Colombier void
2353e12c5d1SDavid du Colombier mountinit(char *server, char *mountpoint)
2363e12c5d1SDavid du Colombier {
2373e12c5d1SDavid du Colombier 	int p[2];
2383e12c5d1SDavid du Colombier 
2393e12c5d1SDavid du Colombier 	/*
2403e12c5d1SDavid du Colombier 	 *  grab a channel and call up the file server
2413e12c5d1SDavid du Colombier 	 */
2427dd7cddfSDavid du Colombier 	s.fd[0] = s.fd[1] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);
2433e12c5d1SDavid du Colombier 	if(s.fd[0] < 0)
2443e12c5d1SDavid du Colombier 		error("opening data");
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 	/*
2473e12c5d1SDavid du Colombier  	 *  mount onto name space
2483e12c5d1SDavid du Colombier 	 */
2493e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2503e12c5d1SDavid du Colombier 		error("pipe failed");
2513e12c5d1SDavid du Colombier 	switch(fork()){
2523e12c5d1SDavid du Colombier 	case 0:
253219b2ee8SDavid du Colombier 		break;
254219b2ee8SDavid du Colombier 	default:
255219b2ee8SDavid du Colombier 		if(amount(p[1], mountpoint, MREPL|MCREATE, "") < 0)
2563e12c5d1SDavid du Colombier 			error("mount failed");
2573e12c5d1SDavid du Colombier 		exits(0);
2583e12c5d1SDavid du Colombier 	case -1:
2593e12c5d1SDavid du Colombier 		error("fork failed\n");
2603e12c5d1SDavid du Colombier /*BUG: no wait!*/
2613e12c5d1SDavid du Colombier 	}
2623e12c5d1SDavid du Colombier 	c.fd[0] = c.fd[1] = p[0];
2633e12c5d1SDavid du Colombier }
2643e12c5d1SDavid du Colombier 
2653e12c5d1SDavid du Colombier void
2663e12c5d1SDavid du Colombier io(void)
2673e12c5d1SDavid du Colombier {
2689a747e4fSDavid du Colombier 	int type;
2693e12c5d1SDavid du Colombier 	Mfile *mf;
2703e12c5d1SDavid du Colombier     loop:
2713e12c5d1SDavid du Colombier 	rcvmsg(&c, &c.thdr);
2729a747e4fSDavid du Colombier 
2739a747e4fSDavid du Colombier 	type = c.thdr.type;
2749a747e4fSDavid du Colombier 
2759a747e4fSDavid du Colombier 	if(statson){
2769a747e4fSDavid du Colombier 		cfsstat.cm[type].n++;
2779a747e4fSDavid du Colombier 		cfsstat.cm[type].s = nsec();
2789a747e4fSDavid du Colombier 	}
2793e12c5d1SDavid du Colombier 	mf = &mfile[c.thdr.fid];
2809a747e4fSDavid du Colombier 	switch(type){
2813e12c5d1SDavid du Colombier 	default:
2823e12c5d1SDavid du Colombier 		error("type");
2833e12c5d1SDavid du Colombier 		break;
2849a747e4fSDavid du Colombier 	case Tversion:
2859a747e4fSDavid du Colombier 		rversion();
2863e12c5d1SDavid du Colombier 		break;
2879a747e4fSDavid du Colombier 	case Tauth:
2889a747e4fSDavid du Colombier 		mf = &mfile[c.thdr.afid];
2899a747e4fSDavid du Colombier 		rauth(mf);
2903e12c5d1SDavid du Colombier 		break;
2913e12c5d1SDavid du Colombier 	case Tflush:
2923e12c5d1SDavid du Colombier 		rflush();
2933e12c5d1SDavid du Colombier 		break;
2943e12c5d1SDavid du Colombier 	case Tattach:
2953e12c5d1SDavid du Colombier 		rattach(mf);
2963e12c5d1SDavid du Colombier 		break;
2973e12c5d1SDavid du Colombier 	case Twalk:
2983e12c5d1SDavid du Colombier 		rwalk(mf);
2993e12c5d1SDavid du Colombier 		break;
3003e12c5d1SDavid du Colombier 	case Topen:
3013e12c5d1SDavid du Colombier 		ropen(mf);
3023e12c5d1SDavid du Colombier 		break;
3033e12c5d1SDavid du Colombier 	case Tcreate:
3043e12c5d1SDavid du Colombier 		rcreate(mf);
3053e12c5d1SDavid du Colombier 		break;
3063e12c5d1SDavid du Colombier 	case Tread:
3073e12c5d1SDavid du Colombier 		rread(mf);
3083e12c5d1SDavid du Colombier 		break;
3093e12c5d1SDavid du Colombier 	case Twrite:
3103e12c5d1SDavid du Colombier 		rwrite(mf);
3113e12c5d1SDavid du Colombier 		break;
3123e12c5d1SDavid du Colombier 	case Tclunk:
3133e12c5d1SDavid du Colombier 		rclunk(mf);
3143e12c5d1SDavid du Colombier 		break;
3153e12c5d1SDavid du Colombier 	case Tremove:
3163e12c5d1SDavid du Colombier 		rremove(mf);
3173e12c5d1SDavid du Colombier 		break;
3183e12c5d1SDavid du Colombier 	case Tstat:
3193e12c5d1SDavid du Colombier 		rstat(mf);
3203e12c5d1SDavid du Colombier 		break;
3213e12c5d1SDavid du Colombier 	case Twstat:
3223e12c5d1SDavid du Colombier 		rwstat(mf);
3233e12c5d1SDavid du Colombier 		break;
3243e12c5d1SDavid du Colombier 	}
3259a747e4fSDavid du Colombier 	if(statson){
3269a747e4fSDavid du Colombier 		cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s;
3279a747e4fSDavid du Colombier 	}
3283e12c5d1SDavid du Colombier 	goto loop;
3293e12c5d1SDavid du Colombier }
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier void
3329a747e4fSDavid du Colombier rversion(void)
333219b2ee8SDavid du Colombier {
3349a747e4fSDavid du Colombier 	if(messagesize > c.thdr.msize)
3359a747e4fSDavid du Colombier 		messagesize = c.thdr.msize;
3369a747e4fSDavid du Colombier 	c.thdr.msize = messagesize;	/* set downstream size */
337219b2ee8SDavid du Colombier 	delegate();
338219b2ee8SDavid du Colombier }
339219b2ee8SDavid du Colombier 
340219b2ee8SDavid du Colombier void
3419a747e4fSDavid du Colombier rauth(Mfile *mf)
3429a747e4fSDavid du Colombier {
3436b6b9ac8SDavid du Colombier 	if(mf->busy)
3446b6b9ac8SDavid du Colombier 		error("auth to used channel");
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier 	if(delegate() == 0){
3476b6b9ac8SDavid du Colombier 		mf->qid = s.rhdr.aqid;
3489a747e4fSDavid du Colombier 		mf->busy = 1;
3499a747e4fSDavid du Colombier 	}
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier 
3529a747e4fSDavid du Colombier void
3533e12c5d1SDavid du Colombier rflush(void)		/* synchronous so easy */
3543e12c5d1SDavid du Colombier {
3553e12c5d1SDavid du Colombier 	sendreply(0);
3563e12c5d1SDavid du Colombier }
3573e12c5d1SDavid du Colombier 
3583e12c5d1SDavid du Colombier void
3593e12c5d1SDavid du Colombier rattach(Mfile *mf)
3603e12c5d1SDavid du Colombier {
3613e12c5d1SDavid du Colombier 	if(delegate() == 0){
3623e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
3633e12c5d1SDavid du Colombier 		mf->busy = 1;
3649a747e4fSDavid du Colombier 		if (statson == 1){
3659a747e4fSDavid du Colombier 			statson++;
3669a747e4fSDavid du Colombier 			rootqid = mf->qid;
3673e12c5d1SDavid du Colombier 		}
3683e12c5d1SDavid du Colombier 	}
3693e12c5d1SDavid du Colombier }
3703e12c5d1SDavid du Colombier 
3713e12c5d1SDavid du Colombier void
3723e12c5d1SDavid du Colombier rwalk(Mfile *mf)
3733e12c5d1SDavid du Colombier {
3749a747e4fSDavid du Colombier 	Mfile *nmf;
3759a747e4fSDavid du Colombier 
3769a747e4fSDavid du Colombier 	nmf = nil;
3779a747e4fSDavid du Colombier 	if(statson
3789a747e4fSDavid du Colombier 	  && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path
3799a747e4fSDavid du Colombier 	  && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){
3809a747e4fSDavid du Colombier 		/* This is the ctl file */
3819a747e4fSDavid du Colombier 		nmf = &mfile[c.thdr.newfid];
3829a747e4fSDavid du Colombier 		if(c.thdr.newfid != c.thdr.fid && nmf->busy)
3839a747e4fSDavid du Colombier 			error("clone to used channel");
3849a747e4fSDavid du Colombier 		nmf = &mfile[c.thdr.newfid];
3859a747e4fSDavid du Colombier 		nmf->qid = ctlqid;
3869a747e4fSDavid du Colombier 		nmf->busy = 1;
3879a747e4fSDavid du Colombier 		c.rhdr.nwqid = 1;
3889a747e4fSDavid du Colombier 		c.rhdr.wqid[0] = ctlqid;
3899a747e4fSDavid du Colombier 		sendreply(0);
3903e12c5d1SDavid du Colombier 		return;
3913e12c5d1SDavid du Colombier 	}
3929a747e4fSDavid du Colombier 	if(c.thdr.newfid != c.thdr.fid){
39322a127bbSDavid du Colombier 		if(c.thdr.newfid >= Nfid)
3949a747e4fSDavid du Colombier 			error("clone nfid out of range");
3959a747e4fSDavid du Colombier 		nmf = &mfile[c.thdr.newfid];
3969a747e4fSDavid du Colombier 		if(nmf->busy)
3979a747e4fSDavid du Colombier 			error("clone to used channel");
3989a747e4fSDavid du Colombier 		nmf = &mfile[c.thdr.newfid];
3999a747e4fSDavid du Colombier 		nmf->qid = mf->qid;
4009a747e4fSDavid du Colombier 		nmf->busy = 1;
4019a747e4fSDavid du Colombier 		mf = nmf; /* Walk mf */
4023e12c5d1SDavid du Colombier 	}
4033e12c5d1SDavid du Colombier 
4049a747e4fSDavid du Colombier 	if(delegate() < 0){	/* complete failure */
4059a747e4fSDavid du Colombier 		if(nmf)
4069a747e4fSDavid du Colombier 			nmf->busy = 0;
4079a747e4fSDavid du Colombier 		return;
4089a747e4fSDavid du Colombier 	}
4099a747e4fSDavid du Colombier 
4109a747e4fSDavid du Colombier 	if(s.rhdr.nwqid == c.thdr.nwname){	/* complete success */
4119a747e4fSDavid du Colombier 		if(s.rhdr.nwqid > 0)
4129a747e4fSDavid du Colombier 			mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1];
4139a747e4fSDavid du Colombier 		return;
4149a747e4fSDavid du Colombier 	}
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier 	/* partial success; release fid */
4179a747e4fSDavid du Colombier 	if(nmf)
4189a747e4fSDavid du Colombier 		nmf->busy = 0;
4193e12c5d1SDavid du Colombier }
4203e12c5d1SDavid du Colombier 
4213e12c5d1SDavid du Colombier void
4223e12c5d1SDavid du Colombier ropen(Mfile *mf)
4233e12c5d1SDavid du Colombier {
4249a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
4259a747e4fSDavid du Colombier 		/* Opening ctl file */
4269a747e4fSDavid du Colombier 		if(c.thdr.mode != OREAD){
4279a747e4fSDavid du Colombier 			sendreply("does not exist");
4289a747e4fSDavid du Colombier 			return;
4299a747e4fSDavid du Colombier 		}
4309a747e4fSDavid du Colombier 		c.rhdr.qid = ctlqid;
4319a747e4fSDavid du Colombier 		c.rhdr.iounit = 0;
4329a747e4fSDavid du Colombier 		sendreply(0);
4339a747e4fSDavid du Colombier 		genstats();
4349a747e4fSDavid du Colombier 		return;
4359a747e4fSDavid du Colombier 	}
4363e12c5d1SDavid du Colombier 	if(delegate() == 0){
4373e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4387dd7cddfSDavid du Colombier 		if(c.thdr.mode & OTRUNC)
4393e12c5d1SDavid du Colombier 			iget(&ic, mf->qid);
4403e12c5d1SDavid du Colombier 	}
4413e12c5d1SDavid du Colombier }
4423e12c5d1SDavid du Colombier 
4433e12c5d1SDavid du Colombier void
4443e12c5d1SDavid du Colombier rcreate(Mfile *mf)
4453e12c5d1SDavid du Colombier {
4469a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
4479a747e4fSDavid du Colombier 		sendreply("exists");
4489a747e4fSDavid du Colombier 		return;
4499a747e4fSDavid du Colombier 	}
4503e12c5d1SDavid du Colombier 	if(delegate() == 0){
4513e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4523e12c5d1SDavid du Colombier 		mf->qid.vers++;
4533e12c5d1SDavid du Colombier 	}
4543e12c5d1SDavid du Colombier }
4553e12c5d1SDavid du Colombier 
4563e12c5d1SDavid du Colombier void
4573e12c5d1SDavid du Colombier rclunk(Mfile *mf)
4583e12c5d1SDavid du Colombier {
4593e12c5d1SDavid du Colombier 	if(!mf->busy){
4603e12c5d1SDavid du Colombier 		sendreply(0);
4613e12c5d1SDavid du Colombier 		return;
4623e12c5d1SDavid du Colombier 	}
4633e12c5d1SDavid du Colombier 	mf->busy = 0;
4643ff48bf5SDavid du Colombier 	delegate();
4653e12c5d1SDavid du Colombier }
4663e12c5d1SDavid du Colombier 
4673e12c5d1SDavid du Colombier void
4683e12c5d1SDavid du Colombier rremove(Mfile *mf)
4693e12c5d1SDavid du Colombier {
4709a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
4719a747e4fSDavid du Colombier 		sendreply("not removed");
4729a747e4fSDavid du Colombier 		return;
4739a747e4fSDavid du Colombier 	}
4743e12c5d1SDavid du Colombier 	mf->busy = 0;
4753e12c5d1SDavid du Colombier 	delegate();
4763e12c5d1SDavid du Colombier }
4773e12c5d1SDavid du Colombier 
4783e12c5d1SDavid du Colombier void
4793e12c5d1SDavid du Colombier rread(Mfile *mf)
4803e12c5d1SDavid du Colombier {
48141fb754aSDavid du Colombier 	int cnt, done;
4823e12c5d1SDavid du Colombier 	long n;
48341fb754aSDavid du Colombier 	vlong off, first;
48441fb754aSDavid du Colombier 	char *cp;
4853e12c5d1SDavid du Colombier 	char data[MAXFDATA];
48641fb754aSDavid du Colombier 	Ibuf *b;
4873e12c5d1SDavid du Colombier 
48841fb754aSDavid du Colombier 	off = c.thdr.offset;
48941fb754aSDavid du Colombier 	first = off;
4903e12c5d1SDavid du Colombier 	cnt = c.thdr.count;
4913e12c5d1SDavid du Colombier 
4929a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
4939a747e4fSDavid du Colombier 		if(cnt > statlen-off)
4949a747e4fSDavid du Colombier 			c.rhdr.count = statlen-off;
4959a747e4fSDavid du Colombier 		else
4969a747e4fSDavid du Colombier 			c.rhdr.count = cnt;
49722a127bbSDavid du Colombier 		if((int)c.rhdr.count < 0){
4989a747e4fSDavid du Colombier 			sendreply("eof");
4999a747e4fSDavid du Colombier 			return;
5009a747e4fSDavid du Colombier 		}
5019a747e4fSDavid du Colombier 		c.rhdr.data = statbuf + off;
5029a747e4fSDavid du Colombier 		sendreply(0);
5039a747e4fSDavid du Colombier 		return;
5049a747e4fSDavid du Colombier 	}
5059a747e4fSDavid du Colombier 	if(mf->qid.type & (QTDIR|QTAUTH)){
5063e12c5d1SDavid du Colombier 		delegate();
5079a747e4fSDavid du Colombier 		if (statson) {
5089a747e4fSDavid du Colombier 			cfsstat.ndirread++;
5099a747e4fSDavid du Colombier 			if(c.rhdr.count > 0){
5109a747e4fSDavid du Colombier 				cfsstat.bytesread += c.rhdr.count;
5119a747e4fSDavid du Colombier 				cfsstat.bytesfromdirs += c.rhdr.count;
5129a747e4fSDavid du Colombier 			}
5139a747e4fSDavid du Colombier 		}
5143e12c5d1SDavid du Colombier 		return;
5153e12c5d1SDavid du Colombier 	}
5163e12c5d1SDavid du Colombier 
5173e12c5d1SDavid du Colombier 	b = iget(&ic, mf->qid);
5183e12c5d1SDavid du Colombier 	if(b == 0){
5199a747e4fSDavid du Colombier 		DPRINT(2, "delegating read\n");
5203e12c5d1SDavid du Colombier 		delegate();
5219a747e4fSDavid du Colombier 		if (statson){
5229a747e4fSDavid du Colombier 			cfsstat.ndelegateread++;
5239a747e4fSDavid du Colombier 			if(c.rhdr.count > 0){
5249a747e4fSDavid du Colombier 				cfsstat.bytesread += c.rhdr.count;
5259a747e4fSDavid du Colombier 				cfsstat.bytesfromserver += c.rhdr.count;
5269a747e4fSDavid du Colombier 			}
5279a747e4fSDavid du Colombier 		}
5283e12c5d1SDavid du Colombier 		return;
5293e12c5d1SDavid du Colombier 	}
5303e12c5d1SDavid du Colombier 
5313e12c5d1SDavid du Colombier 	cp = data;
5323e12c5d1SDavid du Colombier 	done = 0;
5333e12c5d1SDavid du Colombier 	while(cnt>0 && !done){
5349a747e4fSDavid du Colombier 		if(off >= b->inode.length){
53541fb754aSDavid du Colombier 			DPRINT(2, "offset %lld greater than length %lld\n",
53641fb754aSDavid du Colombier 				off, b->inode.length);
5379a747e4fSDavid du Colombier 			break;
5389a747e4fSDavid du Colombier 		}
5393e12c5d1SDavid du Colombier 		n = fread(&ic, b, cp, off, cnt);
5403e12c5d1SDavid du Colombier 		if(n <= 0){
5413e12c5d1SDavid du Colombier 			n = -n;
5423e12c5d1SDavid du Colombier 			if(n==0 || n>cnt)
5433e12c5d1SDavid du Colombier 				n = cnt;
54441fb754aSDavid du Colombier 			DPRINT(2,
54541fb754aSDavid du Colombier 			 "fetch %ld bytes of data from server at offset %lld\n",
54641fb754aSDavid du Colombier 				n, off);
5473e12c5d1SDavid du Colombier 			s.thdr.type = c.thdr.type;
5483e12c5d1SDavid du Colombier 			s.thdr.fid = c.thdr.fid;
5493e12c5d1SDavid du Colombier 			s.thdr.tag = c.thdr.tag;
5503e12c5d1SDavid du Colombier 			s.thdr.offset = off;
5513e12c5d1SDavid du Colombier 			s.thdr.count = n;
55241fb754aSDavid du Colombier 			if(statson)
5539a747e4fSDavid du Colombier 				cfsstat.ndelegateread++;
55480ee5cbfSDavid du Colombier 			if(askserver() < 0){
5553e12c5d1SDavid du Colombier 				sendreply(s.rhdr.ename);
55680ee5cbfSDavid du Colombier 				return;
55780ee5cbfSDavid du Colombier 			}
5583e12c5d1SDavid du Colombier 			if(s.rhdr.count != n)
5593e12c5d1SDavid du Colombier 				done = 1;
5603e12c5d1SDavid du Colombier 			n = s.rhdr.count;
5619a747e4fSDavid du Colombier 			if(n == 0){
5629a747e4fSDavid du Colombier 				/* end of file */
5639a747e4fSDavid du Colombier 				if(b->inode.length > off){
56441fb754aSDavid du Colombier 					DPRINT(2, "file %llud.%ld, length %lld\n",
56541fb754aSDavid du Colombier 						b->inode.qid.path,
56641fb754aSDavid du Colombier 						b->inode.qid.vers, off);
5679a747e4fSDavid du Colombier 					b->inode.length = off;
5689a747e4fSDavid du Colombier 				}
5699a747e4fSDavid du Colombier 				break;
5709a747e4fSDavid du Colombier 			}
5713e12c5d1SDavid du Colombier 			memmove(cp, s.rhdr.data, n);
5723e12c5d1SDavid du Colombier 			fwrite(&ic, b, cp, off, n);
5739a747e4fSDavid du Colombier 			if (statson){
5749a747e4fSDavid du Colombier 				cfsstat.bytestocache += n;
5759a747e4fSDavid du Colombier 				cfsstat.bytesfromserver += n;
5769a747e4fSDavid du Colombier 			}
5779a747e4fSDavid du Colombier 		}else{
5789a747e4fSDavid du Colombier 			DPRINT(2, "fetched %ld bytes from cache\n", n);
57941fb754aSDavid du Colombier 			if(statson)
5809a747e4fSDavid du Colombier 				cfsstat.bytesfromcache += n;
5819a747e4fSDavid du Colombier 		}
5823e12c5d1SDavid du Colombier 		cnt -= n;
5833e12c5d1SDavid du Colombier 		off += n;
5843e12c5d1SDavid du Colombier 		cp += n;
5853e12c5d1SDavid du Colombier 	}
5863e12c5d1SDavid du Colombier 	c.rhdr.data = data;
5873e12c5d1SDavid du Colombier 	c.rhdr.count = off - first;
58841fb754aSDavid du Colombier 	if(statson)
5899a747e4fSDavid du Colombier 		cfsstat.bytesread += c.rhdr.count;
5903e12c5d1SDavid du Colombier 	sendreply(0);
5913e12c5d1SDavid du Colombier }
5923e12c5d1SDavid du Colombier 
5933e12c5d1SDavid du Colombier void
5943e12c5d1SDavid du Colombier rwrite(Mfile *mf)
5953e12c5d1SDavid du Colombier {
5963e12c5d1SDavid du Colombier 	Ibuf *b;
5973e12c5d1SDavid du Colombier 	char buf[MAXFDATA];
5983e12c5d1SDavid du Colombier 
5999a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
6009a747e4fSDavid du Colombier 		sendreply("read only");
6019a747e4fSDavid du Colombier 		return;
6029a747e4fSDavid du Colombier 	}
6039a747e4fSDavid du Colombier 	if(mf->qid.type & (QTDIR|QTAUTH)){
6043e12c5d1SDavid du Colombier 		delegate();
6059a747e4fSDavid du Colombier 		if(statson && c.rhdr.count > 0)
6069a747e4fSDavid du Colombier 			cfsstat.byteswritten += c.rhdr.count;
6073e12c5d1SDavid du Colombier 		return;
6083e12c5d1SDavid du Colombier 	}
6093e12c5d1SDavid du Colombier 
6103e12c5d1SDavid du Colombier 	memmove(buf, c.thdr.data, c.thdr.count);
6113e12c5d1SDavid du Colombier 	if(delegate() < 0)
6123e12c5d1SDavid du Colombier 		return;
6133e12c5d1SDavid du Colombier 
6149a747e4fSDavid du Colombier 	if(s.rhdr.count > 0)
6159a747e4fSDavid du Colombier 		cfsstat.byteswritten += s.rhdr.count;
61641fb754aSDavid du Colombier 	/* don't modify our cache for append-only data; always read from server*/
61741fb754aSDavid du Colombier 	if(mf->qid.type & QTAPPEND)
6189a747e4fSDavid du Colombier 		return;
6193e12c5d1SDavid du Colombier 	b = iget(&ic, mf->qid);
6203e12c5d1SDavid du Colombier 	if(b == 0)
6213e12c5d1SDavid du Colombier 		return;
6229a747e4fSDavid du Colombier 	if (b->inode.length < c.thdr.offset + s.rhdr.count)
6239a747e4fSDavid du Colombier 		b->inode.length = c.thdr.offset + s.rhdr.count;
6243e12c5d1SDavid du Colombier 	mf->qid.vers++;
6259a747e4fSDavid du Colombier 	if (s.rhdr.count != c.thdr.count)
6269a747e4fSDavid du Colombier 		syslog(0, "cfslog", "rhdr.count %ud, thdr.count %ud\n",
6279a747e4fSDavid du Colombier 			s.rhdr.count, c.thdr.count);
6289a747e4fSDavid du Colombier 	if(fwrite(&ic, b, buf, c.thdr.offset, s.rhdr.count) == s.rhdr.count){
6293e12c5d1SDavid du Colombier 		iinc(&ic, b);
6309a747e4fSDavid du Colombier 		if(statson)
6319a747e4fSDavid du Colombier 			cfsstat.bytestocache += s.rhdr.count;
6329a747e4fSDavid du Colombier 	}
6333e12c5d1SDavid du Colombier }
6343e12c5d1SDavid du Colombier 
6353e12c5d1SDavid du Colombier void
6363e12c5d1SDavid du Colombier rstat(Mfile *mf)
6373e12c5d1SDavid du Colombier {
6389a747e4fSDavid du Colombier 	Dir d;
6399a747e4fSDavid du Colombier 
6409a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
6419a747e4fSDavid du Colombier 		genstats();
6429a747e4fSDavid du Colombier 		d.qid = ctlqid;
6439a747e4fSDavid du Colombier 		d.mode = 0444;
6449a747e4fSDavid du Colombier 		d.length = statlen;	/* would be nice to do better */
6459a747e4fSDavid du Colombier 		d.name = "cfsctl";
6469a747e4fSDavid du Colombier 		d.uid = "none";
6479a747e4fSDavid du Colombier 		d.gid = "none";
6489a747e4fSDavid du Colombier 		d.muid = "none";
6499a747e4fSDavid du Colombier 		d.atime = time(nil);
6509a747e4fSDavid du Colombier 		d.mtime = d.atime;
65141fb754aSDavid du Colombier 		c.rhdr.nstat = convD2M(&d, c.rhdr.stat,
65241fb754aSDavid du Colombier 			sizeof c.rhdr - (c.rhdr.stat - (uchar*)&c.rhdr));
6539a747e4fSDavid du Colombier 		sendreply(0);
6549a747e4fSDavid du Colombier 		return;
6559a747e4fSDavid du Colombier 	}
6569a747e4fSDavid du Colombier 	if(delegate() == 0){
6579a747e4fSDavid du Colombier 		Ibuf *b;
6589a747e4fSDavid du Colombier 
6599a747e4fSDavid du Colombier 		convM2D(s.rhdr.stat, s.rhdr.nstat , &d, nil);
6609a747e4fSDavid du Colombier 		mf->qid = d.qid;
6619a747e4fSDavid du Colombier 		b = iget(&ic, mf->qid);
6629a747e4fSDavid du Colombier 		if(b)
6639a747e4fSDavid du Colombier 			b->inode.length = d.length;
6649a747e4fSDavid du Colombier 	}
6653e12c5d1SDavid du Colombier }
6663e12c5d1SDavid du Colombier 
6673e12c5d1SDavid du Colombier void
6683e12c5d1SDavid du Colombier rwstat(Mfile *mf)
6693e12c5d1SDavid du Colombier {
6709a747e4fSDavid du Colombier 	Ibuf *b;
6719a747e4fSDavid du Colombier 
6729a747e4fSDavid du Colombier 	if(statson && ctltest(mf)){
6739a747e4fSDavid du Colombier 		sendreply("read only");
6749a747e4fSDavid du Colombier 		return;
6759a747e4fSDavid du Colombier 	}
6763e12c5d1SDavid du Colombier 	delegate();
6779a747e4fSDavid du Colombier 	if(b = iget(&ic, mf->qid))
6789a747e4fSDavid du Colombier 		b->inode.length = MAXLEN;
6793e12c5d1SDavid du Colombier }
6803e12c5d1SDavid du Colombier 
6813e12c5d1SDavid du Colombier void
68241fb754aSDavid du Colombier error(char *fmt, ...)
68341fb754aSDavid du Colombier {
6849a747e4fSDavid du Colombier 	va_list arg;
6859a747e4fSDavid du Colombier 	static char buf[2048];
6869a747e4fSDavid du Colombier 
6879a747e4fSDavid du Colombier 	va_start(arg, fmt);
6889a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
6899a747e4fSDavid du Colombier 	va_end(arg);
6909a747e4fSDavid du Colombier 	fprint(2, "%s: %s\n", argv0, buf);
6919a747e4fSDavid du Colombier 	exits("error");
6923e12c5d1SDavid du Colombier }
6933e12c5d1SDavid du Colombier 
6943e12c5d1SDavid du Colombier void
6953e12c5d1SDavid du Colombier warning(char *s)
6963e12c5d1SDavid du Colombier {
6977dd7cddfSDavid du Colombier 	fprint(2, "cfs: %s: %r\n", s);
6983e12c5d1SDavid du Colombier }
6993e12c5d1SDavid du Colombier 
7003e12c5d1SDavid du Colombier /*
7013e12c5d1SDavid du Colombier  *  send a reply to the client
7023e12c5d1SDavid du Colombier  */
7033e12c5d1SDavid du Colombier void
7043e12c5d1SDavid du Colombier sendreply(char *err)
7053e12c5d1SDavid du Colombier {
7063e12c5d1SDavid du Colombier 
7073e12c5d1SDavid du Colombier 	if(err){
7083e12c5d1SDavid du Colombier 		c.rhdr.type = Rerror;
7099a747e4fSDavid du Colombier 		c.rhdr.ename = err;
7103e12c5d1SDavid du Colombier 	}else{
7113e12c5d1SDavid du Colombier 		c.rhdr.type = c.thdr.type+1;
7123e12c5d1SDavid du Colombier 		c.rhdr.fid = c.thdr.fid;
7133e12c5d1SDavid du Colombier 	}
7143e12c5d1SDavid du Colombier 	c.rhdr.tag = c.thdr.tag;
7153e12c5d1SDavid du Colombier 	sendmsg(&c, &c.rhdr);
7163e12c5d1SDavid du Colombier }
7173e12c5d1SDavid du Colombier 
7183e12c5d1SDavid du Colombier /*
7193e12c5d1SDavid du Colombier  *  send a request to the server, get the reply, and send that to
7203e12c5d1SDavid du Colombier  *  the client
7213e12c5d1SDavid du Colombier  */
7223e12c5d1SDavid du Colombier int
7233e12c5d1SDavid du Colombier delegate(void)
7243e12c5d1SDavid du Colombier {
7259a747e4fSDavid du Colombier 	int type;
7269a747e4fSDavid du Colombier 
7279a747e4fSDavid du Colombier 	type = c.thdr.type;
7289a747e4fSDavid du Colombier 	if(statson){
7299a747e4fSDavid du Colombier 		cfsstat.sm[type].n++;
7309a747e4fSDavid du Colombier 		cfsstat.sm[type].s = nsec();
7319a747e4fSDavid du Colombier 	}
7329a747e4fSDavid du Colombier 
7333e12c5d1SDavid du Colombier 	sendmsg(&s, &c.thdr);
7343e12c5d1SDavid du Colombier 	rcvmsg(&s, &s.rhdr);
7359a747e4fSDavid du Colombier 
73641fb754aSDavid du Colombier 	if(statson)
7379a747e4fSDavid du Colombier 		cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
7389a747e4fSDavid du Colombier 
7393e12c5d1SDavid du Colombier 	sendmsg(&c, &s.rhdr);
7403e12c5d1SDavid du Colombier 	return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
7413e12c5d1SDavid du Colombier }
7423e12c5d1SDavid du Colombier 
7433e12c5d1SDavid du Colombier /*
7443e12c5d1SDavid du Colombier  *  send a request to the server and get a reply
7453e12c5d1SDavid du Colombier  */
7463e12c5d1SDavid du Colombier int
7473e12c5d1SDavid du Colombier askserver(void)
7483e12c5d1SDavid du Colombier {
7499a747e4fSDavid du Colombier 	int type;
7509a747e4fSDavid du Colombier 
7513e12c5d1SDavid du Colombier 	s.thdr.tag = c.thdr.tag;
7529a747e4fSDavid du Colombier 
7539a747e4fSDavid du Colombier 	type = s.thdr.type;
7549a747e4fSDavid du Colombier 	if(statson){
7559a747e4fSDavid du Colombier 		cfsstat.sm[type].n++;
7569a747e4fSDavid du Colombier 		cfsstat.sm[type].s = nsec();
7579a747e4fSDavid du Colombier 	}
7589a747e4fSDavid du Colombier 
7593e12c5d1SDavid du Colombier 	sendmsg(&s, &s.thdr);
7603e12c5d1SDavid du Colombier 	rcvmsg(&s, &s.rhdr);
7619a747e4fSDavid du Colombier 
76241fb754aSDavid du Colombier 	if(statson)
7639a747e4fSDavid du Colombier 		cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
7649a747e4fSDavid du Colombier 
7653e12c5d1SDavid du Colombier 	return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
7663e12c5d1SDavid du Colombier }
7673e12c5d1SDavid du Colombier 
7683e12c5d1SDavid du Colombier /*
7693e12c5d1SDavid du Colombier  *  send/receive messages with logging
7703e12c5d1SDavid du Colombier  */
7713e12c5d1SDavid du Colombier void
7723e12c5d1SDavid du Colombier sendmsg(P9fs *p, Fcall *f)
7733e12c5d1SDavid du Colombier {
7747dd7cddfSDavid du Colombier 	DPRINT(2, "->%s: %F\n", p->name, f);
7753e12c5d1SDavid du Colombier 
7769a747e4fSDavid du Colombier 	p->len = convS2M(f, datasnd, messagesize);
7779a747e4fSDavid du Colombier 	if(p->len <= 0)
7789a747e4fSDavid du Colombier 		error("convS2M");
7799a747e4fSDavid du Colombier 	if(write(p->fd[1], datasnd, p->len)!=p->len)
7809a747e4fSDavid du Colombier 		error("sendmsg");
7813e12c5d1SDavid du Colombier }
7823e12c5d1SDavid du Colombier 
7833e12c5d1SDavid du Colombier void
7843e12c5d1SDavid du Colombier dump(uchar *p, int len)
7853e12c5d1SDavid du Colombier {
7863e12c5d1SDavid du Colombier 	fprint(2, "%d bytes", len);
78741fb754aSDavid du Colombier 	while(len-- > 0)
7883e12c5d1SDavid du Colombier 		fprint(2, " %.2ux", *p++);
7893e12c5d1SDavid du Colombier 	fprint(2, "\n");
7903e12c5d1SDavid du Colombier }
7913e12c5d1SDavid du Colombier 
7923e12c5d1SDavid du Colombier void
7933e12c5d1SDavid du Colombier rcvmsg(P9fs *p, Fcall *f)
7943e12c5d1SDavid du Colombier {
7959a747e4fSDavid du Colombier 	int olen, rlen;
7967dd7cddfSDavid du Colombier 	char buf[128];
7973e12c5d1SDavid du Colombier 
7983e12c5d1SDavid du Colombier 	olen = p->len;
7999a747e4fSDavid du Colombier 	p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv));
8007dd7cddfSDavid du Colombier 	if(p->len <= 0){
80141fb754aSDavid du Colombier 		snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
80241fb754aSDavid du Colombier 			p->fd[0], p->len);
8037dd7cddfSDavid du Colombier 		error(buf);
8047dd7cddfSDavid du Colombier 	}
8059a747e4fSDavid du Colombier 
8069a747e4fSDavid du Colombier 	if((rlen = convM2S(datarcv, p->len, f)) != p->len)
80741fb754aSDavid du Colombier 		error("rcvmsg format error, expected length %d, got %d",
80841fb754aSDavid du Colombier 			rlen, p->len);
80922a127bbSDavid du Colombier 	if(f->fid >= Nfid){
8103e12c5d1SDavid du Colombier 		fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
81141fb754aSDavid du Colombier 			mname[f->type]? mname[f->type]: "mystery", f->fid);
8123e12c5d1SDavid du Colombier 		dump((uchar*)datasnd, olen);
8133e12c5d1SDavid du Colombier 		dump((uchar*)datarcv, p->len);
8143e12c5d1SDavid du Colombier 		error("rcvmsg fid out of range");
8153e12c5d1SDavid du Colombier 	}
8167dd7cddfSDavid du Colombier 	DPRINT(2, "<-%s: %F\n", p->name, f);
8173e12c5d1SDavid du Colombier }
8189a747e4fSDavid du Colombier 
8199a747e4fSDavid du Colombier int
8209a747e4fSDavid du Colombier ctltest(Mfile *mf)
8219a747e4fSDavid du Colombier {
82241fb754aSDavid du Colombier 	return mf->busy && mf->qid.type == ctlqid.type &&
82341fb754aSDavid du Colombier 		mf->qid.path == ctlqid.path;
8249a747e4fSDavid du Colombier }
8259a747e4fSDavid du Colombier 
8269a747e4fSDavid du Colombier void
8279a747e4fSDavid du Colombier genstats(void)
8289a747e4fSDavid du Colombier {
8299a747e4fSDavid du Colombier 	int i;
8309a747e4fSDavid du Colombier 	char *p;
8319a747e4fSDavid du Colombier 
8329a747e4fSDavid du Colombier 	p = statbuf;
8339a747e4fSDavid du Colombier 
83441fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p,
83541fb754aSDavid du Colombier 		"        Client                          Server\n");
83641fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p,
83741fb754aSDavid du Colombier 	    "   #calls     Δ  ms/call    Δ      #calls     Δ  ms/call    Δ\n");
8389a747e4fSDavid du Colombier 	for (i = 0; i < nelem(cfsstat.cm); i++)
8399a747e4fSDavid du Colombier 		if(cfsstat.cm[i].n || cfsstat.sm[i].n) {
84041fb754aSDavid du Colombier 			p += snprint(p, sizeof statbuf+statbuf-p,
84141fb754aSDavid du Colombier 				"%7lud %7lud ", cfsstat.cm[i].n,
84241fb754aSDavid du Colombier 				cfsstat.cm[i].n - cfsprev.cm[i].n);
8439a747e4fSDavid du Colombier 			if (cfsstat.cm[i].n)
84441fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
84541fb754aSDavid du Colombier 					"%7.3f ", 0.000001*cfsstat.cm[i].t/
84641fb754aSDavid du Colombier 					cfsstat.cm[i].n);
8479a747e4fSDavid du Colombier 			else
84841fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
84941fb754aSDavid du Colombier 					"        ");
8509a747e4fSDavid du Colombier 			if(cfsstat.cm[i].n - cfsprev.cm[i].n)
85141fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
85241fb754aSDavid du Colombier 					"%7.3f ", 0.000001*
85341fb754aSDavid du Colombier 					(cfsstat.cm[i].t - cfsprev.cm[i].t)/
85441fb754aSDavid du Colombier 					(cfsstat.cm[i].n - cfsprev.cm[i].n));
8559a747e4fSDavid du Colombier 			else
85641fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
85741fb754aSDavid du Colombier 					"        ");
85841fb754aSDavid du Colombier 			p += snprint(p, sizeof statbuf+statbuf-p,
85941fb754aSDavid du Colombier 				"%7lud %7lud ", cfsstat.sm[i].n,
86041fb754aSDavid du Colombier 				cfsstat.sm[i].n - cfsprev.sm[i].n);
8619a747e4fSDavid du Colombier 			if (cfsstat.sm[i].n)
86241fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
86341fb754aSDavid du Colombier 					"%7.3f ", 0.000001*cfsstat.sm[i].t/
86441fb754aSDavid du Colombier 					cfsstat.sm[i].n);
8659a747e4fSDavid du Colombier 			else
86641fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
86741fb754aSDavid du Colombier 					"        ");
8689a747e4fSDavid du Colombier 			if(cfsstat.sm[i].n - cfsprev.sm[i].n)
86941fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
87041fb754aSDavid du Colombier 					"%7.3f ", 0.000001*
87141fb754aSDavid du Colombier 					(cfsstat.sm[i].t - cfsprev.sm[i].t)/
87241fb754aSDavid du Colombier 					(cfsstat.sm[i].n - cfsprev.sm[i].n));
8739a747e4fSDavid du Colombier 			else
87441fb754aSDavid du Colombier 				p += snprint(p, sizeof statbuf+statbuf-p,
87541fb754aSDavid du Colombier 					"        ");
87641fb754aSDavid du Colombier 			p += snprint(p, sizeof statbuf+statbuf-p, "%s\n",
87741fb754aSDavid du Colombier 				mname[i]);
8789a747e4fSDavid du Colombier 		}
87941fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndirread\n",
8809a747e4fSDavid du Colombier 		cfsstat.ndirread, cfsstat.ndirread - cfsprev.ndirread);
88141fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelegateread\n",
88241fb754aSDavid du Colombier 		cfsstat.ndelegateread, cfsstat.ndelegateread -
88341fb754aSDavid du Colombier 		cfsprev.ndelegateread);
88441fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ninsert\n",
8859a747e4fSDavid du Colombier 		cfsstat.ninsert, cfsstat.ninsert - cfsprev.ninsert);
88641fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelete\n",
8879a747e4fSDavid du Colombier 		cfsstat.ndelete, cfsstat.ndelete - cfsprev.ndelete);
88841fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud nupdate\n",
8899a747e4fSDavid du Colombier 		cfsstat.nupdate, cfsstat.nupdate - cfsprev.nupdate);
8909a747e4fSDavid du Colombier 
89141fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesread\n",
8929a747e4fSDavid du Colombier 		cfsstat.bytesread, cfsstat.bytesread - cfsprev.bytesread);
89341fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud byteswritten\n",
89441fb754aSDavid du Colombier 		cfsstat.byteswritten, cfsstat.byteswritten -
89541fb754aSDavid du Colombier 		cfsprev.byteswritten);
89641fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromserver\n",
89741fb754aSDavid du Colombier 		cfsstat.bytesfromserver, cfsstat.bytesfromserver -
89841fb754aSDavid du Colombier 		cfsprev.bytesfromserver);
89941fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromdirs\n",
90041fb754aSDavid du Colombier 		cfsstat.bytesfromdirs, cfsstat.bytesfromdirs -
90141fb754aSDavid du Colombier 		cfsprev.bytesfromdirs);
90241fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromcache\n",
90341fb754aSDavid du Colombier 		cfsstat.bytesfromcache, cfsstat.bytesfromcache -
90441fb754aSDavid du Colombier 		cfsprev.bytesfromcache);
90541fb754aSDavid du Colombier 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytestocache\n",
90641fb754aSDavid du Colombier 		cfsstat.bytestocache, cfsstat.bytestocache -
90741fb754aSDavid du Colombier 		cfsprev.bytestocache);
9089a747e4fSDavid du Colombier 	statlen = p - statbuf;
9099a747e4fSDavid du Colombier 	cfsprev = cfsstat;
9109a747e4fSDavid du Colombier }
911