821 lines · 13.1 KB · C
RawDownload
#include	"u.h"#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h" typedef	struct Fid	Fid;typedef	struct Export	Export;typedef	struct Exq	Exq; #define	nil	((void*)0) enum{	Nfidhash	= 1,	MAXRPC		= MAXMSG+MAXFDATA,	MAXDIRREAD	= (MAXFDATA/DIRLEN)*DIRLEN}; struct Export{	Ref	r;	Exq*	work;	Lock	fidlock;	Fid*	fid[Nfidhash];	Chan*	root;	Chan*	io;	Pgrp*	pgrp;	int	npart;	char	part[MAXRPC];}; struct Fid{	Fid*	next;	Fid**	last;	Chan*	chan;	long	offset;	int	fid;	int	ref;		/* fcalls using the fid; locked by Export.Lock */	int	attached;	/* fid attached or cloned but not clunked */}; struct Exq{	Lock	lk;	int	nointr;	int	noresponse;	/* don't respond to this one */	Exq*	next;	int	shut;		/* has been noted for shutdown */	Export*	export;	void*	slave;	Fcall	rpc;	char	buf[MAXRPC];}; struct{	Lock	l;	Qlock	qwait;	Rendez	rwait;	Exq	*head;		/* work waiting for a slave */	Exq	*tail;}exq; static void	exshutdown(Export*);static void	exflush(Export*, int, int);static void	exslave(void*);static void	exfree(Export*);static void	exportproc(Export*); static char*	Exauth(Export*, Fcall*);static char*	Exattach(Export*, Fcall*);static char*	Exclunk(Export*, Fcall*);static char*	Excreate(Export*, Fcall*);static char*	Exopen(Export*, Fcall*);static char*	Exread(Export*, Fcall*);static char*	Exremove(Export*, Fcall*);static char*	Exstat(Export*, Fcall*);static char*	Exwalk(Export*, Fcall*);static char*	Exwrite(Export*, Fcall*);static char*	Exwstat(Export*, Fcall*);static char*	Exversion(Export*, Fcall*); static char	*(*fcalls[Tmax])(Export*, Fcall*); static char	Enofid[]   = "no such fid";static char	Eseekdir[] = "can't seek on a directory";static char	Ereaddir[] = "unaligned read of a directory";static int	exdebug = 0; intsysexport(int fd){	Chan *c;	Export *fs; 	if(waserror())		return -1; 	c = fdtochan(fd, ORDWR, 1, 1);	poperror();	c->flag |= CMSG; 	fs = mallocz(sizeof(Export));	fs->r.ref = 1;	fs->pgrp = up->pgrp;	refinc(&fs->pgrp->r);	refinc(&up->slash->r);	fs->root = up->slash;	refinc(&fs->root->r);	fs->root = domount(fs->root);	fs->io = c; 	exportproc(fs); 	return 0;} static voidexportinit(void){	lock(&exq.l);	if(fcalls[Tversion] != nil) {		unlock(&exq.l);		return;	} 	fmtinstall('F', fcallfmt);	fmtinstall('D', dirfmt);	fmtinstall('M', dirmodefmt);	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);} voidexportproc(Export *fs){	Exq *q;	char *buf;	int n, cn, len; 	exportinit(); 	for(;;){		q = mallocz(sizeof(Exq));		if(q == 0)			panic("no memory"); 		q->rpc.data = q->buf + MAXMSG; 		buf = q->buf;		len = MAXRPC;		if(fs->npart) {			memmove(buf, fs->part, fs->npart);			buf += fs->npart;			len -= fs->npart;			goto chk;		}		for(;;) {			if(waserror())				goto bad; 			n = (*devtab[fs->io->type].read)(fs->io, buf, len, 0);			poperror(); 			if(n <= 0)				goto bad; 			buf += n;			len -= n;	chk:			n = buf - q->buf; 			/* convM2S returns size of correctly decoded message */			cn = convM2S(q->buf, &q->rpc, n);			if(cn < 0){				iprint("bad message type in devmnt\n");				goto bad;			}			if(cn > 0) {				n -= cn;				if(n < 0){					iprint("negative size in devmnt");					goto bad;				}				fs->npart = n;				if(n != 0)					memmove(fs->part, q->buf+cn, n);				break;			}		}		if(exdebug)			iprint("export %d <- %F\n", getpid(), &q->rpc); 		if(q->rpc.type == Tflush){			exflush(fs, q->rpc.tag, q->rpc.oldtag);			free(q);			continue;		} 		q->export = fs;		refinc(&fs->r); 		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.first == nil) {			n = thread("exportfs", exslave, nil);/* iprint("launch export (pid=%ux)\n", n); */		}		rendwakeup(&exq.rwait);	}bad:	free(q);	exshutdown(fs);	exfree(fs);} voidexflush(Export *fs, int flushtag, int tag){	Exq *q, **last;	int n;	Fcall fc;	char buf[MAXMSG]; 	/* hasn't been started? */	lock(&exq.l);	last = &exq.head;	for(q = exq.head; q != nil; q = q->next){		if(q->export == fs && q->rpc.tag == tag){			*last = q->next;			unlock(&exq.l);			exfree(fs);			free(q);			goto Respond;		}		last = &q->next;	}	unlock(&exq.l); 	/* in progress? */	lock(&fs->r.l);	for(q = fs->work; q != nil; q = q->next){		if(q->rpc.tag == tag && !q->noresponse){			lock(&q->lk);			q->noresponse = 1;			if(!q->nointr)				intr(q->slave);			unlock(&q->lk);			unlock(&fs->r.l);			goto Respond;			return;		}	}	unlock(&fs->r.l); if(exdebug) iprint("exflush: did not find rpc: %d\n", tag); Respond:	fc.type = Rflush;	fc.tag = flushtag;	n = convS2M(&fc, buf);if(exdebug) iprint("exflush -> %F\n", &fc);	if(!waserror()){		(*devtab[fs->io->type].write)(fs->io, buf, n, 0);		poperror();	}} voidexshutdown(Export *fs){	Exq *q, **last; 	lock(&exq.l);	last = &exq.head;	for(q = exq.head; q != nil; q = *last){		if(q->export == fs){			*last = q->next;			exfree(fs);			free(q);			continue;		}		last = &q->next;	}	unlock(&exq.l); 	lock(&fs->r.l);	q = fs->work;	while(q != nil){		if(q->shut){			q = q->next;			continue;		}		q->shut = 1;		unlock(&fs->r.l);	/*	postnote(q->slave, 1, "interrupted", NUser);	*/		iprint("postnote 2!\n");		lock(&fs->r.l);		q = fs->work;	}	unlock(&fs->r.l);} voidexfree(Export *fs){	Fid *f, *n;	int i; 	if(refdec(&fs->r) != 0)		return;	closepgrp(fs->pgrp);	cclose(fs->root);	cclose(fs->io);	for(i = 0; i < Nfidhash; i++){		for(f = fs->fid[i]; f != nil; f = n){			if(f->chan != nil)				cclose(f->chan);			n = f->next;			free(f);		}	}	free(fs);} intexwork(void *a){	return exq.head != nil;} voidexslave(void *a){	Export *fs;	Exq *q, *t, **last;	char *err;	int n;/*	closepgrp(up->pgrp);	up->pgrp = nil;*/	for(;;){		qlock(&exq.qwait);		rendsleep(&exq.rwait, exwork, nil); 		lock(&exq.l);		q = exq.head;		if(q == nil) {			unlock(&exq.l);			qunlock(&exq.qwait);			continue;		}		exq.head = q->next;		q->slave = curthread();		unlock(&exq.l); 		qunlock(&exq.qwait); 		q->noresponse = 0;		q->nointr = 0;		fs = q->export;		lock(&fs->r.l);		q->next = fs->work;		fs->work = q;		unlock(&fs->r.l); 		up->pgrp = q->export->pgrp; 		if(exdebug > 1)			iprint("exslave dispatch %d %F\n", getpid(), &q->rpc); 		if(waserror()){			iprint("exslave err %r\n");			err = up->errstr;			goto Err;		}		if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])			err = "bad fcall type";		else			err = (*fcalls[q->rpc.type])(fs, &q->rpc); 		poperror();		Err:;		q->rpc.type++;		if(err){			q->rpc.type = Rerror;			strncpy(q->rpc.ename, err, ERRLEN);		}		n = convS2M(&q->rpc, q->buf); 		if(exdebug)			iprint("exslve %d -> %F\n", getpid(), &q->rpc); 		lock(&q->lk);		if(q->noresponse == 0){			q->nointr = 1;			clearintr();			if(!waserror()){				(*devtab[fs->io->type].write)(fs->io, q->buf, n, 0);				poperror();			}		}		unlock(&q->lk); 		/*		 * exflush might set noresponse at this point, but		 * setting noresponse means don't send a response now;		 * it's okay that we sent a response already.		 */		if(exdebug > 1)			iprint("exslave %d written %d\n", getpid(), q->rpc.tag); 		lock(&fs->r.l);		last = &fs->work;		for(t = fs->work; t != nil; t = t->next){			if(t == q){				*last = q->next;				break;			}			last = &t->next;		}		unlock(&fs->r.l); 		exfree(q->export);		free(q);	}	iprint("exslave shut down");	threadexit();} Fid*Exmkfid(Export *fs, int fid){	ulong h;	Fid *f, *nf; 	nf = mallocz(sizeof(Fid));	if(nf == nil)		return nil;	lock(&fs->fidlock);	h = fid % Nfidhash;	for(f = fs->fid[h]; f != nil; f = f->next){		if(f->fid == fid){			unlock(&fs->fidlock);			free(nf);			return nil;		}	} 	nf->next = fs->fid[h];	if(nf->next != nil)		nf->next->last = &nf->next;	nf->last = &fs->fid[h];	fs->fid[h] = nf; 	nf->fid = fid;	nf->ref = 1;	nf->attached = 1;	nf->offset = 0;	nf->chan = nil;	unlock(&fs->fidlock);	return nf;} Fid*Exgetfid(Export *fs, int fid){	Fid *f;	ulong h; 	lock(&fs->fidlock);	h = fid % Nfidhash;	for(f = fs->fid[h]; f; f = f->next) {		if(f->fid == fid){			if(f->attached == 0)				break;			f->ref++;			unlock(&fs->fidlock);			return f;		}

Lines 1–500 of 821.