⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exportfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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;		}	}	unlock(&fs->fidlock);	return nil;}voidExputfid(Export *fs, Fid *f){	lock(&fs->fidlock);	f->ref--;	if(f->ref == 0 && f->attached == 0){		if(f->chan != nil)			cclose(f->chan);		f->chan = nil;		*f->last = f->next;		if(f->next != nil)			f->next->last = f->last;		unlock(&fs->fidlock);		free(f);		return;	}	unlock(&fs->fidlock);}char*Exsession(Export *e, Fcall *rpc){	memset(rpc->authid, 0, sizeof(rpc->authid));	memset(rpc->authdom, 0, sizeof(rpc->authdom));	memset(rpc->chal, 0, sizeof(rpc->chal));	return nil;}char*Exauth(Export *e, Fcall *f){	return "authentication not required";}char*Exattach(Export *fs, Fcall *rpc){	Fid *f;	f = Exmkfid(fs, rpc->fid);	if(f == nil)		return Einuse;	if(waserror()){		f->attached = 0;		Exputfid(fs, f);		return up->errstr;	}	f->chan = clone(fs->root, nil);	poperror();	rpc->qid = f->chan->qid;	Exputfid(fs, f);	return nil;}char*Exclone(Export *fs, Fcall *rpc){	Fid *f, *nf;	if(rpc->fid == rpc->newfid)		return Einuse;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	nf = Exmkfid(fs, rpc->newfid);	if(nf == nil){		Exputfid(fs, f);		return Einuse;	}	if(waserror()){		Exputfid(fs, f);		Exputfid(fs, nf);		return up->errstr;	}	nf->chan = clone(f->chan, nil);	poperror();	Exputfid(fs, f);	Exputfid(fs, nf);	return nil;}char*Exclunk(Export *fs, Fcall *rpc){	Fid *f;	f = Exgetfid(fs, rpc->fid);	if(f != nil){		f->attached = 0;		Exputfid(fs, f);	}	return nil;}char*Exwalk(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = walk(f->chan, rpc->name, 1);	if(c == nil)		error(Enonexist);	poperror();	f->chan = c;	rpc->qid = c->qid;	Exputfid(fs, f);	return nil;}char*Exopen(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = f->chan;	c = (*devtab[c->type].open)(c, rpc->mode);	poperror();	f->chan = c;	f->offset = 0;	rpc->qid = f->chan->qid;	Exputfid(fs, f);	return nil;}char*Excreate(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = f->chan;	if(c->mnt && !(c->flag&CCREATE))		c = createdir(c);	(*devtab[c->type].create)(c, rpc->name, rpc->mode, rpc->perm);	poperror();	f->chan = c;	rpc->qid = f->chan->qid;	Exputfid(fs, f);	return nil;}char*Exread(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	long off;	int dir, n, seek;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	c = f->chan;	dir = c->qid.path & CHDIR;	if(dir){		rpc->count -= rpc->count%DIRLEN;		if(rpc->offset%DIRLEN || rpc->count==0){			Exputfid(fs, f);			return Ereaddir;		}		if(f->offset > rpc->offset){			Exputfid(fs, f);			return Eseekdir;		}	}	if(waserror()) {		Exputfid(fs, f);		return up->errstr;	}	for(;;){		n = rpc->count;		seek = 0;		off = rpc->offset;		if(dir && f->offset != off){			off = f->offset;			n = rpc->offset - off;			if(n > MAXDIRREAD)				n = MAXDIRREAD;			seek = 1;		}		if(dir && c->mnt != nil)			n = unionread(c, rpc->data, n);		else{			c->offset = off;			n = (*devtab[c->type].read)(c, rpc->data, n, off);		}		if(n == 0 || !seek)			break;		f->offset = off + n;		c->offset += n;	}	rpc->count = n;	poperror();	Exputfid(fs, f);	return nil;}char*Exwrite(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = f->chan;	if(c->qid.path & CHDIR)		error(Eisdir);	rpc->count = (*devtab[c->type].write)(c, rpc->data, rpc->count, rpc->offset);	poperror();	Exputfid(fs, f);	return nil;}char*Exstat(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = f->chan;	(*devtab[c->type].stat)(c, rpc->stat);	poperror();	Exputfid(fs, f);	return nil;}char*Exwstat(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = f->chan;	(*devtab[c->type].wstat)(c, rpc->stat);	poperror();	Exputfid(fs, f);	return nil;}char*Exremove(Export *fs, Fcall *rpc){	Fid *f;	Chan *c;	f = Exgetfid(fs, rpc->fid);	if(f == nil)		return Enofid;	if(waserror()){		Exputfid(fs, f);		return up->errstr;	}	c = f->chan;	(*devtab[c->type].remove)(c);	poperror();	/*	 * chan is already clunked by remove.	 * however, we need to recover the chan,	 * and follow sysremove's lead in making to point to root.	 */	c->type = 0;	f->attached = 0;	Exputfid(fs, f);	return nil;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -