Charles.Forsyth20061220965a0ca19 years agoHistory
1330 lines · 23.5 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"kernel.h" typedef	struct Fid	Fid;typedef	struct Export	Export;typedef	struct Exq	Exq;typedef	struct Uqid Uqid; enum{	Nfidhash	= 32,	Nqidhash = 32,	QIDMASK = ((vlong)1<<48)-1,	MAXFDATA	= 8192,	MAXRPCDEF		= IOHDRSZ+MAXFDATA,	/* initial/default */	MAXRPCMAX	= IOHDRSZ+64*1024,	/* most every allowed */	MSGHDRSZ	= BIT32SZ+BIT8SZ+BIT16SZ}; struct Export{	Lock;	Ref	r;	Exq*	work;	Lock	fidlock;	Fid*	fid[Nfidhash];	QLock	qidlock;	Uqid*	qids[Nqidhash];	ulong	pathgen;	Chan*	io;	Chan*	root;	Pgrp*	pgrp;	Egrp*	egrp;	Fgrp*	fgrp;	int	async;	int	readonly;	int	msize;	char*	user;}; struct Fid{	Fid*	next;	Fid**	last;	Chan*	chan;	int	fid;	int	ref;		/* fcalls using the fid; locked by Export.Lock */	vlong	offset;	/* last offset used (within directory) */	int	attached;	/* fid attached or cloned but not clunked */	Uqid*	qid;	/* generated qid */}; struct Uqid{	Ref;	int	type;	int	dev;	vlong	oldpath;	vlong	newpath;	Uqid*	next;}; struct Exq{	Lock;	int	busy;	/* fcall in progress */	int	finished;	/* will do no more work on this request or flushes */	Exq*	next;	int	shut;		/* has been noted for shutdown */	Exq*	flush;	/* queued flush requests */	Exq*	flusht;	/* tail of flush queue */	Export*	export;	Proc*	slave;	Fcall	in, out;	uchar*	buf;	int	bsize;}; struct{	Lock	l;	QLock	qwait;	Rendez	rwait;	Exq	*head;		/* work waiting for a slave */	Exq	*tail;}exq; static void	exshutdown(Export*);static int	exflushed(Export*, Exq*);static void	exslave(void*);static void	exfree(Export*);static void	exfreeq(Exq*);static void	exportproc(void*);static void	exreply(Exq*, char*);static int	exisroot(Export*, Chan*);static Uqid*	uqidalloc(Export*, Chan*);static void		freeuqid(Export*, Uqid*); static char*	Exversion(Export*, Fcall*, Fcall*);static char*	Exauth(Export*, Fcall*, Fcall*);static char*	Exattach(Export*, Fcall*, Fcall*);static char*	Exclunk(Export*, Fcall*, Fcall*);static char*	Excreate(Export*, Fcall*, Fcall*);static char*	Exopen(Export*, Fcall*, Fcall*);static char*	Exread(Export*, Fcall*, Fcall*);static char*	Exremove(Export*, Fcall*, Fcall*);static char*	Exstat(Export*, Fcall*, Fcall*);static char*	Exwalk(Export*, Fcall*, Fcall*);static char*	Exwrite(Export*, Fcall*, Fcall*);static char*	Exwstat(Export*, Fcall*, Fcall*); static char	*(*fcalls[Tmax])(Export*, Fcall*, Fcall*); static char	Enofid[]   = "no such fid";static char	Eseekdir[] = "can't seek on a directory";static char	Eopen[]	= "walk of open fid";static char	Emode[] = "open/create -- unknown mode";static char	Edupfid[]	= "fid in use";static char	Eaccess[] = "read/write -- not open in suitable mode";static char	Ecount[] = "read/write -- count too big";int	exdebug = 0; intexport(int fd, char *dir, int async){	Chan *c, *dc;	Pgrp *pg;	Egrp *eg;	Export *fs; 	if(waserror())		return -1;	c = fdtochan(up->env->fgrp, fd, ORDWR, 1, 1);	poperror(); 	if(waserror()){		cclose(c);		return -1;	}	dc = namec(dir, Atodir, 0, 0);	poperror(); 	fs = malloc(sizeof(Export));	if(fs == nil){		cclose(c);		cclose(dc);		error(Enomem);	} 	fs->r.ref = 1;	pg = up->env->pgrp;	fs->pgrp = pg;	incref(pg);	eg = up->env->egrp;	fs->egrp = eg;	if(eg != nil)		incref(eg);	fs->fgrp = newfgrp(nil);	kstrdup(&fs->user, up->env->user);	fs->root = dc;	fs->io = c;	fs->pathgen = 0;	fs->msize = 0;	c->flag |= CMSG;	fs->async = async; 	if(async){		if(waserror())			return -1;		kproc("exportfs", exportproc, fs, 0);		poperror();	}else		exportproc(fs); 	return 0;} static voidexportinit(void){	lock(&exq.l);	if(fcalls[Tversion] != nil) {		unlock(&exq.l);		return;	}	fcalls[Tversion] = Exversion;	fcalls[Tauth] = Exauth;	fcalls[Tattach] = Exattach;	fcalls[Twalk] = Exwalk;	fcalls[Topen] = Exopen;	fcalls[Tcreate] = Excreate;	fcalls[Tread] = Exread;	fcalls[Twrite] = Exwrite;	fcalls[Tclunk] = Exclunk;	fcalls[Tremove] = Exremove;	fcalls[Tstat] = Exstat;	fcalls[Twstat] = Exwstat;	unlock(&exq.l);} static intexisroot(Export *fs, Chan *c){	return eqchan(fs->root, c, 1);} static intexreadn(Chan *c, void *buf, int n){	int nr, t; 	if(waserror())		return -1;	for(nr = 0; nr < n;){		t = devtab[c->type]->read(c, (char*)buf+nr, n-nr, 0);		if(t <= 0)			break;		nr += t;	}	poperror();	return nr;} static intexreadmsg(Chan *c, void *a, uint n){	int m, len;	uchar *buf; 	buf = a;	m = exreadn(c, buf, BIT32SZ);	if(m < BIT32SZ){		if(m < 0)			return -1;		return 0;	}	len = GBIT32(buf);	if(len <= BIT32SZ || len > n){		kwerrstr("bad length in Styx message header");		return -1;	}	len -= BIT32SZ;	m = exreadn(c, buf+BIT32SZ, len);	if(m < len){		if(m < 0)			return -1;		return 0;	}	return BIT32SZ+m;} static voidexportproc(void *a){	Exq *q;	int async, msize;	int n, type;	Export *fs = a; 	exportinit(); 	for(;;){ 		msize = fs->msize;		if(msize == 0)			msize = MAXRPCDEF;		for(n=0;; n++){	/* we don't use smalloc, to avoid memset */			q = mallocz(sizeof(*q)+msize, 0);			if(q != nil || n > 6000)				break;			if(n%600 == 0)				print("exportproc %ld: waiting for memory (%d) for request\n", up->pid, msize);			tsleep(&up->sleep, return0, nil, 100);		}		if(q == nil){			kwerrstr("out of memory: read request");			n = -1;			break;		}		memset(q, 0, sizeof(*q));		q->buf = (uchar*)q + sizeof(*q);		q->bsize = msize; 		n = exreadmsg(fs->io, q->buf, msize);	/* TO DO: avoid copy */		if(n <= 0)			break;		if(convM2S(q->buf, n, &q->in) != n){			kwerrstr("bad T-message");			n = -1;			break;		}		type = q->in.type;		if(type < Tversion || type >= Tmax || type&1 || type == Terror){			kwerrstr("invalid T-message type %d", type);			n = -1;			break;		} 		if(exdebug)			print("export %ld <- %F\n", up->pid, &q->in); 		q->out.type = type+1;		q->out.tag = q->in.tag; 		q->export = fs;		incref(&fs->r); 		if(fs->readonly){			switch(type){			case Topen:				if((q->in.mode & (ORCLOSE|OTRUNC|3)) == OREAD)					break;				/* FALL THROUGH */			case Tcreate:			case Twrite:			case Tremove:			case Twstat:				q->out.type = Rerror;				q->out.ename = "file system read only";				exreply(q, "exportproc");				exfreeq(q);				continue;			}		} 		if(q->in.type == Tflush){			if(exflushed(fs, q)){				/* not yet started or not found (flush arrived after reply); we reply */				if(exdebug)					print("export: flush %d\n", q->in.oldtag);				exreply(q, "exportproc");				exfreeq(q);			}			continue;		} 		lock(&exq.l);		if(exq.head == nil)			exq.head = q;		else			exq.tail->next = q;		q->next = nil;		exq.tail = q;		unlock(&exq.l);		if(exq.qwait.head == nil)			kproc("exslave", exslave, nil, 0);		wakeup(&exq.rwait);	} 	if(exdebug){		if(n < 0)			print("exportproc %ld shut down: %s\n", up->pid, up->env->errstr);		else			print("exportproc %ld shut down\n", up->pid);	} 	free(q);	exshutdown(fs);	async = fs->async;	exfree(fs); 	if(async)		pexit("mount shut down", 0);} static intexflushed(Export *fs, Exq *fq){	Exq *q, **last;	ulong pid; 	/* not yet started? */	lock(&exq.l);	for(last = &exq.head; (q = *last) != nil; last = &q->next)		if(q->export == fs && q->in.tag == fq->in.oldtag){			*last = q->next;			unlock(&exq.l);			/* not yet started: discard, and Rflush */			exfreeq(q);			return 1;		}	unlock(&exq.l); 	/* tricky case: in progress */	lock(fs);	for(q = fs->work; q != nil; q = q->next)		if(q->in.tag == fq->in.oldtag){			pid = 0;			lock(q);			if(q->finished){				/* slave replied and emptied its flush queue; we can Rflush now */				unlock(q);				return 1;			}			/* append to slave's flush queue */			fq->next = nil;			if(q->flush != nil)				q->flusht->next = fq;			else				q->flush = fq;			q->flusht = fq;			if(q->busy){				pid = q->slave->pid;				swiproc(q->slave, 0);			}			unlock(q);			unlock(fs);			if(exdebug && pid)				print("export: swiproc %ld to flush %d\n", pid, fq->in.oldtag);			return 0;		}	unlock(fs); 	/* not found */	return 1;} static voidexfreeq(Exq *q){	Exq *fq; 	while((fq = q->flush) != nil){		q->flush = fq->next;		exfree(fq->export);		free(fq);	}	exfree(q->export);	free(q);} static voidexshutdown(Export *fs){	Exq *q, **last; 	/* work not started */	lock(&exq.l);	for(last = &exq.head; (q = *last) != nil;)		if(q->export == fs){			*last = q->next;			exfreeq(q);		}else			last = &q->next;	unlock(&exq.l); 	/* tell slaves to abandon work in progress */	lock(fs);	while((q = fs->work) != nil){		fs->work = q->next;		lock(q);		q->shut = 1;		swiproc(q->slave, 0);	/* whether busy or not */		unlock(q);	}	unlock(fs);} static voidexfreefids(Export *fs){	Fid *f, *n;	int i; 	for(i = 0; i < Nfidhash; i++){		for(f = fs->fid[i]; f != nil; f = n){			n = f->next;			f->attached = 0;			if(f->ref == 0) {				if(f->chan != nil)					cclose(f->chan);				freeuqid(fs, f->qid);				free(f);			} else				print("exfreefids: busy fid\n");		}	}} static voidexfree(Export *fs){	if(exdebug)		print("export p/s %ld free %p ref %ld\n", up->pid, fs, fs->r.ref);	if(decref(&fs->r) != 0)		return;	closepgrp(fs->pgrp);	closeegrp(fs->egrp);	closefgrp(fs->fgrp);	cclose(fs->root);	cclose(fs->io);	exfreefids(fs);	free(fs->user);	free(fs);}

Lines 1–500 of 1330.