930 lines · 17.4 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h> #include "cformat.h"#include "lru.h"#include "bcache.h"#include "disk.h"#include "inode.h"#include "file.h"#include "stats.h" enum{	Nfid=		10240,}; /* maximum length of a file */enum { MAXLEN = ~0ULL >> 1 }; typedef struct Mfile Mfile;typedef struct Ram Ram;typedef struct P9fs P9fs; struct Mfile{	Qid	qid;	char	busy;}; Mfile	mfile[Nfid];Icache	ic;int	debug, statson, noauth, openserver; struct P9fs{	int	fd[2];	Fcall	rhdr;	Fcall	thdr;	long	len;	char	*name;}; P9fs	c;	/* client conversation */P9fs	s;	/* server conversation */ struct Cfsstat  cfsstat, cfsprev;char	statbuf[2048];int	statlen; #define	MAXFDATA	8192	/* i/o size for read/write */ int		messagesize = MAXFDATA+IOHDRSZ; uchar	datasnd[MAXFDATA + IOHDRSZ];uchar	datarcv[MAXFDATA + IOHDRSZ]; Qid	rootqid;Qid	ctlqid = {0x5555555555555555LL, 0, 0}; void	rversion(void);void	rauth(Mfile*);void	rflush(void);void	rattach(Mfile*);void	rwalk(Mfile*);void	ropen(Mfile*);void	rcreate(Mfile*);void	rread(Mfile*);void	rwrite(Mfile*);void	rclunk(Mfile*);void	rremove(Mfile*);void	rstat(Mfile*);void	rwstat(Mfile*);void	error(char*, ...);void	warning(char*);void	mountinit(char*, char*);void	io(void);void	sendreply(char*);void	sendmsg(P9fs*, Fcall*);void	rcvmsg(P9fs*, Fcall*);int	delegate(void);int	askserver(void);void	cachesetup(int, char*, char*);int	ctltest(Mfile*);void	genstats(void); char *mname[]={	[Tversion]		"Tversion",	[Tauth]	"Tauth",	[Tflush]	"Tflush",	[Tattach]	"Tattach",	[Twalk]		"Twalk",	[Topen]		"Topen",	[Tcreate]	"Tcreate",	[Tclunk]	"Tclunk",	[Tread]		"Tread",	[Twrite]	"Twrite",	[Tremove]	"Tremove",	[Tstat]		"Tstat",	[Twstat]	"Twstat",	[Rversion]	"Rversion",	[Rauth]	"Rauth",	[Rerror]	"Rerror",	[Rflush]	"Rflush",	[Rattach]	"Rattach",	[Rwalk]		"Rwalk",	[Ropen]		"Ropen",	[Rcreate]	"Rcreate",	[Rclunk]	"Rclunk",	[Rread]		"Rread",	[Rwrite]	"Rwrite",	[Rremove]	"Rremove",	[Rstat]		"Rstat",	[Rwstat]	"Rwstat",			0,}; voidusage(void){	fprint(2, "usage:\tcfs -s [-dknrS] [-f partition]\n");	fprint(2, "\tcfs [-a netaddr | -F srv] [-dknrS] [-f partition] [mntpt]\n");	exits("usage");} voidmain(int argc, char *argv[]){	int std, format, chkid;	char *part, *server, *mtpt;	NetConnInfo *snci; 	std = 0;	format = 0;	chkid = 1;	part = "/dev/sdC0/cache";	server = "tcp!fs";	mtpt = "/tmp"; 	ARGBEGIN{	case 'a':		server = EARGF(usage());		break;	case 'd':		debug = 1;		break;	case 'f':		part = EARGF(usage());		break;	case 'F':		server = EARGF(usage());		openserver = 1;		break;	case 'k':		chkid = 0;		break;	case 'n':		noauth = 1;		break;	case 'r':		format = 1;		break;	case 'S':		statson = 1;		break;	case 's':		std = 1;		break;	default:		usage();	}ARGEND	if(argc && *argv)		mtpt = *argv; 	if(debug)		fmtinstall('F', fcallfmt); 	c.name = "client";	s.name = "server";	if(std){		c.fd[0] = c.fd[1] = 1;		s.fd[0] = s.fd[1] = 0;	}else		mountinit(server, mtpt); 	if(chkid){		if((snci = getnetconninfo(nil, s.fd[0])) == nil)			/* Failed to lookup information; format */			cachesetup(1, nil, part);		else			/* Do partition check */			cachesetup(0, snci->raddr, part);	}else		/* Obey -f w/o regard to cache vs. remote server */		cachesetup(format, nil, part); 	switch(fork()){	case 0:		io();		exits("");	case -1:		error("fork");	default:		exits("");	}} voidcachesetup(int format, char *name, char *partition){	int f;	int secsize;	int inodes;	int blocksize; 	secsize = 512;	inodes = 1024;	blocksize = 4*1024; 	f = open(partition, ORDWR);	if(f < 0)		error("opening partition"); 	if(format || iinit(&ic, f, secsize, name) < 0){		/*		 * If we need to format and don't have a name, fall		 * back to our old behavior of using "bootes"		 */		name = (name == nil? "bootes": name);		if(iformat(&ic, f, inodes, name, blocksize, secsize) < 0)			error("formatting failed");	}} voidmountinit(char *server, char *mountpoint){	int err;	int p[2]; 	/*	 *  grab a channel and call up the file server	 */	if (openserver)		s.fd[0] = open(server, ORDWR);	else		s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);	if(s.fd[0] < 0)		error("opening data: %r");	s.fd[1] = s.fd[0]; 	/* 	 *  mount onto name space	 */	if(pipe(p) < 0)		error("pipe failed");	switch(fork()){	case 0:		break;	default:		if (noauth)			err = mount(p[1], -1, mountpoint, MREPL|MCREATE, "");		else			err = amount(p[1], mountpoint, MREPL|MCREATE, "");		if (err < 0)			error("mount failed: %r");		exits(0);	case -1:		error("fork failed\n");/*BUG: no wait!*/	}	c.fd[0] = c.fd[1] = p[0];} voidio(void){	int type;	Mfile *mf;    loop:	rcvmsg(&c, &c.thdr); 	type = c.thdr.type; 	if(statson){		cfsstat.cm[type].n++;		cfsstat.cm[type].s = nsec();	}	mf = &mfile[c.thdr.fid];	switch(type){	default:		error("type");		break;	case Tversion:		rversion();		break;	case Tauth:		mf = &mfile[c.thdr.afid];		rauth(mf);		break;	case Tflush:		rflush();		break;	case Tattach:		rattach(mf);		break;	case Twalk:		rwalk(mf);		break;	case Topen:		ropen(mf);		break;	case Tcreate:		rcreate(mf);		break;	case Tread:		rread(mf);		break;	case Twrite:		rwrite(mf);		break;	case Tclunk:		rclunk(mf);		break;	case Tremove:		rremove(mf);		break;	case Tstat:		rstat(mf);		break;	case Twstat:		rwstat(mf);		break;	}	if(statson){		cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s;	}	goto loop;} voidrversion(void){	if(messagesize > c.thdr.msize)		messagesize = c.thdr.msize;	c.thdr.msize = messagesize;	/* set downstream size */	delegate();} voidrauth(Mfile *mf){	if(mf->busy)		error("auth to used channel"); 	if(delegate() == 0){		mf->qid = s.rhdr.aqid;		mf->busy = 1;	}} voidrflush(void)		/* synchronous so easy */{	sendreply(0);} voidrattach(Mfile *mf){	if(delegate() == 0){		mf->qid = s.rhdr.qid;		mf->busy = 1;		if (statson == 1){			statson++;			rootqid = mf->qid;		}	}} voidrwalk(Mfile *mf){	Mfile *nmf; 	nmf = nil;	if(statson	  && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path	  && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){		/* This is the ctl file */		nmf = &mfile[c.thdr.newfid];		if(c.thdr.newfid != c.thdr.fid && nmf->busy)			error("clone to used channel");		nmf = &mfile[c.thdr.newfid];		nmf->qid = ctlqid;		nmf->busy = 1;		c.rhdr.nwqid = 1;		c.rhdr.wqid[0] = ctlqid;		sendreply(0);		return;	}	if(c.thdr.newfid != c.thdr.fid){		if(c.thdr.newfid >= Nfid)			error("clone nfid out of range");		nmf = &mfile[c.thdr.newfid];		if(nmf->busy)			error("clone to used channel");		nmf = &mfile[c.thdr.newfid];		nmf->qid = mf->qid;		nmf->busy = 1;		mf = nmf; /* Walk mf */	} 	if(delegate() < 0){	/* complete failure */		if(nmf)			nmf->busy = 0;		return;	} 	if(s.rhdr.nwqid == c.thdr.nwname){	/* complete success */		if(s.rhdr.nwqid > 0)			mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1];		return;	} 	/* partial success; release fid */	if(nmf)		nmf->busy = 0;} voidropen(Mfile *mf){	if(statson && ctltest(mf)){		/* Opening ctl file */		if(c.thdr.mode != OREAD){			sendreply("does not exist");			return;		}		c.rhdr.qid = ctlqid;		c.rhdr.iounit = 0;		sendreply(0);		genstats();		return;	}	if(delegate() == 0){		mf->qid = s.rhdr.qid;		if(c.thdr.mode & OTRUNC)			iget(&ic, mf->qid);	}} voidrcreate(Mfile *mf){	if(statson && ctltest(mf)){		sendreply("exists");		return;	}	if(delegate() == 0){		mf->qid = s.rhdr.qid;		mf->qid.vers++;	}} voidrclunk(Mfile *mf){	if(!mf->busy){		sendreply(0);		return;	}	mf->busy = 0;	delegate();} voidrremove(Mfile *mf){	if(statson && ctltest(mf)){		sendreply("not removed");		return;	}	mf->busy = 0;	delegate();} voidrread(Mfile *mf){

Lines 1–500 of 930.