xref: /plan9/sys/src/cmd/vnc/exportfs.c (revision 530efdcaff4f66de5639ecb5f7b3370f61b181e0)
19a747e4fSDavid du Colombier #include	<u.h>
29a747e4fSDavid du Colombier #include	<libc.h>
39a747e4fSDavid du Colombier #include	<fcall.h>
49a747e4fSDavid du Colombier #include	"compat.h"
59a747e4fSDavid du Colombier #include	"error.h"
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier typedef	struct Fid	Fid;
89a747e4fSDavid du Colombier typedef	struct Export	Export;
99a747e4fSDavid du Colombier typedef	struct Exq	Exq;
109a747e4fSDavid du Colombier typedef	struct Exwork	Exwork;
119a747e4fSDavid du Colombier 
129a747e4fSDavid du Colombier enum
139a747e4fSDavid du Colombier {
14*530efdcaSDavid du Colombier 	Nfidhash	= 32,
159a747e4fSDavid du Colombier 	Maxfdata	= 8192,
169a747e4fSDavid du Colombier 	Maxrpc		= IOHDRSZ + Maxfdata,
179a747e4fSDavid du Colombier };
189a747e4fSDavid du Colombier 
199a747e4fSDavid du Colombier struct Export
209a747e4fSDavid du Colombier {
219a747e4fSDavid du Colombier 	Ref	r;
229a747e4fSDavid du Colombier 	Exq*	work;
239a747e4fSDavid du Colombier 	Lock	fidlock;
249a747e4fSDavid du Colombier 	Fid*	fid[Nfidhash];
259a747e4fSDavid du Colombier 	int	io;		/* fd to read/write */
269a747e4fSDavid du Colombier 	int	iounit;
279a747e4fSDavid du Colombier 	int	nroots;
289a747e4fSDavid du Colombier 	Chan	**roots;
299a747e4fSDavid du Colombier };
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier struct Fid
329a747e4fSDavid du Colombier {
339a747e4fSDavid du Colombier 	Fid*	next;
349a747e4fSDavid du Colombier 	Fid**	last;
359a747e4fSDavid du Colombier 	Chan*	chan;
369a747e4fSDavid du Colombier 	long	offset;
379a747e4fSDavid du Colombier 	int	fid;
389a747e4fSDavid du Colombier 	int	ref;		/* fcalls using the fid; locked by Export.Lock */
399a747e4fSDavid du Colombier 	int	attached;	/* fid attached or cloned but not clunked */
409a747e4fSDavid du Colombier };
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier struct Exq
439a747e4fSDavid du Colombier {
449a747e4fSDavid du Colombier 	Lock	lk;
459a747e4fSDavid du Colombier 	int	responding;	/* writing out reply message */
469a747e4fSDavid du Colombier 	int	noresponse;	/* don't respond to this one */
479a747e4fSDavid du Colombier 	Exq*	next;
489a747e4fSDavid du Colombier 	int	shut;		/* has been noted for shutdown */
499a747e4fSDavid du Colombier 	Export*	export;
509a747e4fSDavid du Colombier 	void*	slave;
519a747e4fSDavid du Colombier 	Fcall	rpc;
529a747e4fSDavid du Colombier 	uchar	buf[Maxrpc];
539a747e4fSDavid du Colombier };
549a747e4fSDavid du Colombier 
559a747e4fSDavid du Colombier struct Exwork
569a747e4fSDavid du Colombier {
579a747e4fSDavid du Colombier 	Lock	l;
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier 	int	ref;
609a747e4fSDavid du Colombier 
619a747e4fSDavid du Colombier 	int	nwaiters;	/* queue of slaves waiting for work */
629a747e4fSDavid du Colombier 	QLock	qwait;
639a747e4fSDavid du Colombier 	Rendez	rwait;
649a747e4fSDavid du Colombier 
659a747e4fSDavid du Colombier 	Exq	*head;		/* work waiting for a slave */
669a747e4fSDavid du Colombier 	Exq	*tail;
679a747e4fSDavid du Colombier };
689a747e4fSDavid du Colombier 
699a747e4fSDavid du Colombier Exwork exq;
709a747e4fSDavid du Colombier 
719a747e4fSDavid du Colombier static void	exshutdown(Export*);
729a747e4fSDavid du Colombier static void	exflush(Export*, int, int);
739a747e4fSDavid du Colombier static void	exslave(void*);
749a747e4fSDavid du Colombier static void	exfree(Export*);
759a747e4fSDavid du Colombier static void	exportproc(Export*);
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier static char*	Exattach(Export*, Fcall*, uchar*);
789a747e4fSDavid du Colombier static char*	Exauth(Export*, Fcall*, uchar*);
799a747e4fSDavid du Colombier static char*	Exclunk(Export*, Fcall*, uchar*);
809a747e4fSDavid du Colombier static char*	Excreate(Export*, Fcall*, uchar*);
819a747e4fSDavid du Colombier static char*	Exversion(Export*, Fcall*, uchar*);
829a747e4fSDavid du Colombier static char*	Exopen(Export*, Fcall*, uchar*);
839a747e4fSDavid du Colombier static char*	Exread(Export*, Fcall*, uchar*);
849a747e4fSDavid du Colombier static char*	Exremove(Export*, Fcall*, uchar*);
859a747e4fSDavid du Colombier static char*	Exsession(Export*, Fcall*, uchar*);
869a747e4fSDavid du Colombier static char*	Exstat(Export*, Fcall*, uchar*);
879a747e4fSDavid du Colombier static char*	Exwalk(Export*, Fcall*, uchar*);
889a747e4fSDavid du Colombier static char*	Exwrite(Export*, Fcall*, uchar*);
899a747e4fSDavid du Colombier static char*	Exwstat(Export*, Fcall*, uchar*);
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier static char	*(*fcalls[Tmax])(Export*, Fcall*, uchar*);
929a747e4fSDavid du Colombier 
939a747e4fSDavid du Colombier static char	Enofid[]   = "no such fid";
949a747e4fSDavid du Colombier static char	Eseekdir[] = "can't seek on a directory";
959a747e4fSDavid du Colombier static char	Ereaddir[] = "unaligned read of a directory";
969a747e4fSDavid du Colombier static int	exdebug = 0;
979a747e4fSDavid du Colombier 
989a747e4fSDavid du Colombier int
sysexport(int fd,Chan ** roots,int nroots)999a747e4fSDavid du Colombier sysexport(int fd, Chan **roots, int nroots)
1009a747e4fSDavid du Colombier {
1019a747e4fSDavid du Colombier 	Export *fs;
1029a747e4fSDavid du Colombier 
1039a747e4fSDavid du Colombier 	fs = smalloc(sizeof(Export));
1049a747e4fSDavid du Colombier 	fs->r.ref = 1;
1059a747e4fSDavid du Colombier 	fs->io = fd;
1069a747e4fSDavid du Colombier 	fs->roots = roots;
1079a747e4fSDavid du Colombier 	fs->nroots = nroots;
1089a747e4fSDavid du Colombier 
1099a747e4fSDavid du Colombier 	exportproc(fs);
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier 	return 0;
1129a747e4fSDavid du Colombier }
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier static void
exportinit(void)1159a747e4fSDavid du Colombier exportinit(void)
1169a747e4fSDavid du Colombier {
1179a747e4fSDavid du Colombier 	lock(&exq.l);
1189a747e4fSDavid du Colombier 	exq.ref++;
1199a747e4fSDavid du Colombier 	if(fcalls[Tversion] != nil){
1209a747e4fSDavid du Colombier 		unlock(&exq.l);
1219a747e4fSDavid du Colombier 		return;
1229a747e4fSDavid du Colombier 	}
1239a747e4fSDavid du Colombier 
1249a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
1259a747e4fSDavid du Colombier 	fcalls[Tversion] = Exversion;
1269a747e4fSDavid du Colombier 	fcalls[Tauth] = Exauth;
1279a747e4fSDavid du Colombier 	fcalls[Tattach] = Exattach;
1289a747e4fSDavid du Colombier 	fcalls[Twalk] = Exwalk;
1299a747e4fSDavid du Colombier 	fcalls[Topen] = Exopen;
1309a747e4fSDavid du Colombier 	fcalls[Tcreate] = Excreate;
1319a747e4fSDavid du Colombier 	fcalls[Tread] = Exread;
1329a747e4fSDavid du Colombier 	fcalls[Twrite] = Exwrite;
1339a747e4fSDavid du Colombier 	fcalls[Tclunk] = Exclunk;
1349a747e4fSDavid du Colombier 	fcalls[Tremove] = Exremove;
1359a747e4fSDavid du Colombier 	fcalls[Tstat] = Exstat;
1369a747e4fSDavid du Colombier 	fcalls[Twstat] = Exwstat;
1379a747e4fSDavid du Colombier 	unlock(&exq.l);
1389a747e4fSDavid du Colombier }
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier static void
exportproc(Export * fs)1419a747e4fSDavid du Colombier exportproc(Export *fs)
1429a747e4fSDavid du Colombier {
1439a747e4fSDavid du Colombier 	Exq *q;
1449a747e4fSDavid du Colombier 	int n, ed;
1459a747e4fSDavid du Colombier 
1469a747e4fSDavid du Colombier 	exportinit();
1479a747e4fSDavid du Colombier 	ed = errdepth(-1);
1489a747e4fSDavid du Colombier 	for(;;){
1499a747e4fSDavid du Colombier 		errdepth(ed);
1509a747e4fSDavid du Colombier 		q = smalloc(sizeof(Exq));
1519a747e4fSDavid du Colombier 
1529a747e4fSDavid du Colombier 		n = read9pmsg(fs->io, q->buf, Maxrpc);
1539a747e4fSDavid du Colombier 		if(n <= 0 || convM2S(q->buf, n, &q->rpc) != n)
1549a747e4fSDavid du Colombier 			goto bad;
1559a747e4fSDavid du Colombier 
1569a747e4fSDavid du Colombier 		if(exdebug)
1579a747e4fSDavid du Colombier 			print("export %d <- %F\n", getpid(), &q->rpc);
1589a747e4fSDavid du Colombier 
1599a747e4fSDavid du Colombier 		if(q->rpc.type == Tflush){
1609a747e4fSDavid du Colombier 			exflush(fs, q->rpc.tag, q->rpc.oldtag);
1619a747e4fSDavid du Colombier 			free(q);
1629a747e4fSDavid du Colombier 			continue;
1639a747e4fSDavid du Colombier 		}
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 		q->export = fs;
1669a747e4fSDavid du Colombier 		incref(&fs->r);
1679a747e4fSDavid du Colombier 
1689a747e4fSDavid du Colombier 		lock(&exq.l);
1699a747e4fSDavid du Colombier 		if(exq.head == nil)
1709a747e4fSDavid du Colombier 			exq.head = q;
1719a747e4fSDavid du Colombier 		else
1729a747e4fSDavid du Colombier 			exq.tail->next = q;
1739a747e4fSDavid du Colombier 		q->next = nil;
1749a747e4fSDavid du Colombier 		exq.tail = q;
1759a747e4fSDavid du Colombier 		n = exq.nwaiters;
1769a747e4fSDavid du Colombier 		if(n)
1779a747e4fSDavid du Colombier 			exq.nwaiters = n - 1;
1789a747e4fSDavid du Colombier 		unlock(&exq.l);
1799a747e4fSDavid du Colombier 		if(!n)
1809a747e4fSDavid du Colombier 			kproc("exportfs", exslave, nil);
1819a747e4fSDavid du Colombier 		rendwakeup(&exq.rwait);
1829a747e4fSDavid du Colombier 	}
1839a747e4fSDavid du Colombier bad:
1849a747e4fSDavid du Colombier 	free(q);
1859a747e4fSDavid du Colombier 	if(exdebug)
1869a747e4fSDavid du Colombier 		fprint(2, "export proc shutting down: %r\n");
1879a747e4fSDavid du Colombier 	exshutdown(fs);
1889a747e4fSDavid du Colombier 	exfree(fs);
1899a747e4fSDavid du Colombier }
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier static void
exflush(Export * fs,int flushtag,int tag)1929a747e4fSDavid du Colombier exflush(Export *fs, int flushtag, int tag)
1939a747e4fSDavid du Colombier {
1949a747e4fSDavid du Colombier 	Exq *q, **last;
1959a747e4fSDavid du Colombier 	Fcall fc;
1969a747e4fSDavid du Colombier 	uchar buf[Maxrpc];
1979a747e4fSDavid du Colombier 	int n;
1989a747e4fSDavid du Colombier 
1999a747e4fSDavid du Colombier 	/* hasn't been started? */
2009a747e4fSDavid du Colombier 	lock(&exq.l);
2019a747e4fSDavid du Colombier 	last = &exq.head;
2029a747e4fSDavid du Colombier 	for(q = exq.head; q != nil; q = q->next){
2039a747e4fSDavid du Colombier 		if(q->export == fs && q->rpc.tag == tag){
2049a747e4fSDavid du Colombier 			*last = q->next;
2059a747e4fSDavid du Colombier 			unlock(&exq.l);
2069a747e4fSDavid du Colombier 			exfree(fs);
2079a747e4fSDavid du Colombier 			free(q);
2089a747e4fSDavid du Colombier 			goto Respond;
2099a747e4fSDavid du Colombier 		}
2109a747e4fSDavid du Colombier 		last = &q->next;
2119a747e4fSDavid du Colombier 	}
2129a747e4fSDavid du Colombier 	unlock(&exq.l);
2139a747e4fSDavid du Colombier 
2149a747e4fSDavid du Colombier 	/* in progress? */
2159a747e4fSDavid du Colombier 	lock(&fs->r);
2169a747e4fSDavid du Colombier 	for(q = fs->work; q != nil; q = q->next){
2179a747e4fSDavid du Colombier 		if(q->rpc.tag == tag){
2189a747e4fSDavid du Colombier 			lock(&q->lk);
2199a747e4fSDavid du Colombier 			q->noresponse = 1;
2209a747e4fSDavid du Colombier 			if(!q->responding)
2219a747e4fSDavid du Colombier 				rendintr(q->slave);
2229a747e4fSDavid du Colombier 			unlock(&q->lk);
2239a747e4fSDavid du Colombier 			break;
2249a747e4fSDavid du Colombier 		}
2259a747e4fSDavid du Colombier 	}
2269a747e4fSDavid du Colombier 	unlock(&fs->r);
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier Respond:
2299a747e4fSDavid du Colombier 	fc.type = Rflush;
2309a747e4fSDavid du Colombier 	fc.tag = flushtag;
2319a747e4fSDavid du Colombier 
2329a747e4fSDavid du Colombier 	n = convS2M(&fc, buf, Maxrpc);
2339a747e4fSDavid du Colombier 	if(n == 0)
2349a747e4fSDavid du Colombier 		panic("convS2M error on write");
2359a747e4fSDavid du Colombier 	if(write(fs->io, buf, n) != n)
2369a747e4fSDavid du Colombier 		panic("mount write");
2379a747e4fSDavid du Colombier }
2389a747e4fSDavid du Colombier 
2399a747e4fSDavid du Colombier static void
exshutdown(Export * fs)2409a747e4fSDavid du Colombier exshutdown(Export *fs)
2419a747e4fSDavid du Colombier {
2429a747e4fSDavid du Colombier 	Exq *q, **last;
2439a747e4fSDavid du Colombier 
2449a747e4fSDavid du Colombier 	lock(&exq.l);
2459a747e4fSDavid du Colombier 	last = &exq.head;
2469a747e4fSDavid du Colombier 	for(q = exq.head; q != nil; q = *last){
2479a747e4fSDavid du Colombier 		if(q->export == fs){
2489a747e4fSDavid du Colombier 			*last = q->next;
2499a747e4fSDavid du Colombier 			exfree(fs);
2509a747e4fSDavid du Colombier 			free(q);
2519a747e4fSDavid du Colombier 			continue;
2529a747e4fSDavid du Colombier 		}
2539a747e4fSDavid du Colombier 		last = &q->next;
2549a747e4fSDavid du Colombier 	}
2559a747e4fSDavid du Colombier 
2569a747e4fSDavid du Colombier 	/*
2579a747e4fSDavid du Colombier 	 * cleanly shut down the slaves if this is the last fs around
2589a747e4fSDavid du Colombier 	 */
2599a747e4fSDavid du Colombier 	exq.ref--;
2609a747e4fSDavid du Colombier 	if(!exq.ref)
2619a747e4fSDavid du Colombier 		rendwakeup(&exq.rwait);
2629a747e4fSDavid du Colombier 	unlock(&exq.l);
2639a747e4fSDavid du Colombier 
2649a747e4fSDavid du Colombier 	/*
2659a747e4fSDavid du Colombier 	 * kick any sleepers
2669a747e4fSDavid du Colombier 	 */
2679a747e4fSDavid du Colombier 	lock(&fs->r);
2689a747e4fSDavid du Colombier 	for(q = fs->work; q != nil; q = q->next){
2699a747e4fSDavid du Colombier 		lock(&q->lk);
2709a747e4fSDavid du Colombier 		q->noresponse = 1;
2719a747e4fSDavid du Colombier 		if(!q->responding)
2729a747e4fSDavid du Colombier 			rendintr(q->slave);
2739a747e4fSDavid du Colombier 		unlock(&q->lk);
2749a747e4fSDavid du Colombier 	}
2759a747e4fSDavid du Colombier 	unlock(&fs->r);
2769a747e4fSDavid du Colombier }
2779a747e4fSDavid du Colombier 
2789a747e4fSDavid du Colombier static void
exfree(Export * fs)2799a747e4fSDavid du Colombier exfree(Export *fs)
2809a747e4fSDavid du Colombier {
2819a747e4fSDavid du Colombier 	Fid *f, *n;
2829a747e4fSDavid du Colombier 	int i;
2839a747e4fSDavid du Colombier 
2849a747e4fSDavid du Colombier 	if(decref(&fs->r) != 0)
2859a747e4fSDavid du Colombier 		return;
2869a747e4fSDavid du Colombier 	for(i = 0; i < Nfidhash; i++){
2879a747e4fSDavid du Colombier 		for(f = fs->fid[i]; f != nil; f = n){
2889a747e4fSDavid du Colombier 			if(f->chan != nil)
2899a747e4fSDavid du Colombier 				cclose(f->chan);
2909a747e4fSDavid du Colombier 			n = f->next;
2919a747e4fSDavid du Colombier 			free(f);
2929a747e4fSDavid du Colombier 		}
2939a747e4fSDavid du Colombier 	}
2949a747e4fSDavid du Colombier 	free(fs);
2959a747e4fSDavid du Colombier }
2969a747e4fSDavid du Colombier 
2979a747e4fSDavid du Colombier static int
exwork(void *)2989a747e4fSDavid du Colombier exwork(void *)
2999a747e4fSDavid du Colombier {
3009a747e4fSDavid du Colombier 	int work;
3019a747e4fSDavid du Colombier 
3029a747e4fSDavid du Colombier 	lock(&exq.l);
3039a747e4fSDavid du Colombier 	work = exq.head != nil || !exq.ref;
3049a747e4fSDavid du Colombier 	unlock(&exq.l);
3059a747e4fSDavid du Colombier 	return work;
3069a747e4fSDavid du Colombier }
3079a747e4fSDavid du Colombier 
3089a747e4fSDavid du Colombier static void
exslave(void *)3099a747e4fSDavid du Colombier exslave(void *)
3109a747e4fSDavid du Colombier {
3119a747e4fSDavid du Colombier 	Export *fs;
3129a747e4fSDavid du Colombier 	Exq *q, *t, **last;
3139a747e4fSDavid du Colombier 	char *volatile err;
3149a747e4fSDavid du Colombier 	int n, ed;
3159a747e4fSDavid du Colombier 
3166b6b9ac8SDavid du Colombier 	while(waserror())
3176b6b9ac8SDavid du Colombier 		fprint(2, "exslave %d errored out of loop -- heading back in!\n", getpid());
3189a747e4fSDavid du Colombier 	ed = errdepth(-1);
3199a747e4fSDavid du Colombier 	for(;;){
3209a747e4fSDavid du Colombier 		errdepth(ed);
3219a747e4fSDavid du Colombier 		qlock(&exq.qwait);
3229a747e4fSDavid du Colombier 		if(waserror()){
3239a747e4fSDavid du Colombier 			qunlock(&exq.qwait);
3249a747e4fSDavid du Colombier 			nexterror();
3259a747e4fSDavid du Colombier 		}
3269a747e4fSDavid du Colombier 		rendsleep(&exq.rwait, exwork, nil);
3279a747e4fSDavid du Colombier 
3289a747e4fSDavid du Colombier 		lock(&exq.l);
3299a747e4fSDavid du Colombier 		if(!exq.ref){
3309a747e4fSDavid du Colombier 			unlock(&exq.l);
3319a747e4fSDavid du Colombier 			poperror();
3329a747e4fSDavid du Colombier 			qunlock(&exq.qwait);
3339a747e4fSDavid du Colombier 			break;
3349a747e4fSDavid du Colombier 		}
3359a747e4fSDavid du Colombier 		q = exq.head;
3369a747e4fSDavid du Colombier 		if(q == nil){
3379a747e4fSDavid du Colombier 			unlock(&exq.l);
3389a747e4fSDavid du Colombier 			poperror();
3399a747e4fSDavid du Colombier 			qunlock(&exq.qwait);
3409a747e4fSDavid du Colombier 			continue;
3419a747e4fSDavid du Colombier 		}
3429a747e4fSDavid du Colombier 		exq.head = q->next;
3439a747e4fSDavid du Colombier 		if(exq.head == nil)
3449a747e4fSDavid du Colombier 			exq.tail = nil;
3459a747e4fSDavid du Colombier 		poperror();
3469a747e4fSDavid du Colombier 		qunlock(&exq.qwait);
3479a747e4fSDavid du Colombier 
3489a747e4fSDavid du Colombier 		/*
3499a747e4fSDavid du Colombier 		 * put the job on the work queue before it's
3509a747e4fSDavid du Colombier 		 * visible as off of the head queue, so it's always
3519a747e4fSDavid du Colombier 		 * findable for flushes and shutdown
3529a747e4fSDavid du Colombier 		 */
3539a747e4fSDavid du Colombier 		q->slave = up;
3549a747e4fSDavid du Colombier 		q->noresponse = 0;
3559a747e4fSDavid du Colombier 		q->responding = 0;
3569a747e4fSDavid du Colombier 		rendclearintr();
3579a747e4fSDavid du Colombier 		fs = q->export;
3589a747e4fSDavid du Colombier 		lock(&fs->r);
3599a747e4fSDavid du Colombier 		q->next = fs->work;
3609a747e4fSDavid du Colombier 		fs->work = q;
3619a747e4fSDavid du Colombier 		unlock(&fs->r);
3629a747e4fSDavid du Colombier 
3639a747e4fSDavid du Colombier 		unlock(&exq.l);
3649a747e4fSDavid du Colombier 
3659a747e4fSDavid du Colombier 		if(exdebug > 1)
3669a747e4fSDavid du Colombier 			print("exslave dispatch %d %F\n", getpid(), &q->rpc);
3679a747e4fSDavid du Colombier 
3689a747e4fSDavid du Colombier 		if(waserror()){
3699a747e4fSDavid du Colombier 			print("exslave err %r\n");
3709a747e4fSDavid du Colombier 			err = up->error;
3719a747e4fSDavid du Colombier 		}else{
3729a747e4fSDavid du Colombier 			if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
3739a747e4fSDavid du Colombier 				err = "bad fcall type";
3749a747e4fSDavid du Colombier 			else
3759a747e4fSDavid du Colombier 				err = (*fcalls[q->rpc.type])(fs, &q->rpc, &q->buf[IOHDRSZ]);
3769a747e4fSDavid du Colombier 			poperror();
3779a747e4fSDavid du Colombier 		}
3789a747e4fSDavid du Colombier 
3799a747e4fSDavid du Colombier 		q->rpc.type++;
3809a747e4fSDavid du Colombier 		if(err){
3819a747e4fSDavid du Colombier 			q->rpc.type = Rerror;
3829a747e4fSDavid du Colombier 			q->rpc.ename = err;
3839a747e4fSDavid du Colombier 		}
3849a747e4fSDavid du Colombier 		n = convS2M(&q->rpc, q->buf, Maxrpc);
3859a747e4fSDavid du Colombier 
3869a747e4fSDavid du Colombier 		if(exdebug)
3879a747e4fSDavid du Colombier 			print("exslave %d -> %F\n", getpid(), &q->rpc);
3889a747e4fSDavid du Colombier 
3899a747e4fSDavid du Colombier 		lock(&q->lk);
3909a747e4fSDavid du Colombier 		if(!q->noresponse){
3919a747e4fSDavid du Colombier 			q->responding = 1;
3929a747e4fSDavid du Colombier 			unlock(&q->lk);
3939a747e4fSDavid du Colombier 			write(fs->io, q->buf, n);
3949a747e4fSDavid du Colombier 		}else
3959a747e4fSDavid du Colombier 			unlock(&q->lk);
3969a747e4fSDavid du Colombier 
3979a747e4fSDavid du Colombier 		/*
3989a747e4fSDavid du Colombier 		 * exflush might set noresponse at this point, but
3999a747e4fSDavid du Colombier 		 * setting noresponse means don't send a response now;
4009a747e4fSDavid du Colombier 		 * it's okay that we sent a response already.
4019a747e4fSDavid du Colombier 		 */
4029a747e4fSDavid du Colombier 		if(exdebug > 1)
4039a747e4fSDavid du Colombier 			print("exslave %d written %d\n", getpid(), q->rpc.tag);
4049a747e4fSDavid du Colombier 
4059a747e4fSDavid du Colombier 		lock(&fs->r);
4069a747e4fSDavid du Colombier 		last = &fs->work;
4079a747e4fSDavid du Colombier 		for(t = fs->work; t != nil; t = t->next){
4089a747e4fSDavid du Colombier 			if(t == q){
4099a747e4fSDavid du Colombier 				*last = q->next;
4109a747e4fSDavid du Colombier 				break;
4119a747e4fSDavid du Colombier 			}
4129a747e4fSDavid du Colombier 			last = &t->next;
4139a747e4fSDavid du Colombier 		}
4149a747e4fSDavid du Colombier 		unlock(&fs->r);
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier 		exfree(q->export);
4179a747e4fSDavid du Colombier 		free(q);
4189a747e4fSDavid du Colombier 
4196b6b9ac8SDavid du Colombier 		rendclearintr();
4209a747e4fSDavid du Colombier 		lock(&exq.l);
4219a747e4fSDavid du Colombier 		exq.nwaiters++;
4229a747e4fSDavid du Colombier 		unlock(&exq.l);
4239a747e4fSDavid du Colombier 	}
4249a747e4fSDavid du Colombier 	if(exdebug)
4259a747e4fSDavid du Colombier 		fprint(2, "export slaveshutting down\n");
4269a747e4fSDavid du Colombier 	kexit();
4279a747e4fSDavid du Colombier }
4289a747e4fSDavid du Colombier 
4299a747e4fSDavid du Colombier Fid*
Exmkfid(Export * fs,int fid)4309a747e4fSDavid du Colombier Exmkfid(Export *fs, int fid)
4319a747e4fSDavid du Colombier {
4329a747e4fSDavid du Colombier 	ulong h;
4339a747e4fSDavid du Colombier 	Fid *f, *nf;
4349a747e4fSDavid du Colombier 
4359a747e4fSDavid du Colombier 	nf = mallocz(sizeof(Fid), 1);
4369a747e4fSDavid du Colombier 	if(nf == nil)
4379a747e4fSDavid du Colombier 		return nil;
4389a747e4fSDavid du Colombier 	lock(&fs->fidlock);
4399a747e4fSDavid du Colombier 	h = fid % Nfidhash;
4409a747e4fSDavid du Colombier 	for(f = fs->fid[h]; f != nil; f = f->next){
4419a747e4fSDavid du Colombier 		if(f->fid == fid){
4429a747e4fSDavid du Colombier 			unlock(&fs->fidlock);
4439a747e4fSDavid du Colombier 			free(nf);
4449a747e4fSDavid du Colombier 			return nil;
4459a747e4fSDavid du Colombier 		}
4469a747e4fSDavid du Colombier 	}
4479a747e4fSDavid du Colombier 
4489a747e4fSDavid du Colombier 	nf->next = fs->fid[h];
4499a747e4fSDavid du Colombier 	if(nf->next != nil)
4509a747e4fSDavid du Colombier 		nf->next->last = &nf->next;
4519a747e4fSDavid du Colombier 	nf->last = &fs->fid[h];
4529a747e4fSDavid du Colombier 	fs->fid[h] = nf;
4539a747e4fSDavid du Colombier 
4549a747e4fSDavid du Colombier 	nf->fid = fid;
4559a747e4fSDavid du Colombier 	nf->ref = 1;
4569a747e4fSDavid du Colombier 	nf->attached = 1;
4579a747e4fSDavid du Colombier 	nf->offset = 0;
4589a747e4fSDavid du Colombier 	nf->chan = nil;
4599a747e4fSDavid du Colombier 	unlock(&fs->fidlock);
4609a747e4fSDavid du Colombier 	return nf;
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier Fid*
Exgetfid(Export * fs,int fid)4649a747e4fSDavid du Colombier Exgetfid(Export *fs, int fid)
4659a747e4fSDavid du Colombier {
4669a747e4fSDavid du Colombier 	Fid *f;
4679a747e4fSDavid du Colombier 	ulong h;
4689a747e4fSDavid du Colombier 
4699a747e4fSDavid du Colombier 	lock(&fs->fidlock);
4709a747e4fSDavid du Colombier 	h = fid % Nfidhash;
4719a747e4fSDavid du Colombier 	for(f = fs->fid[h]; f; f = f->next){
4729a747e4fSDavid du Colombier 		if(f->fid == fid){
4739a747e4fSDavid du Colombier 			if(f->attached == 0)
4749a747e4fSDavid du Colombier 				break;
4759a747e4fSDavid du Colombier 			f->ref++;
4769a747e4fSDavid du Colombier 			unlock(&fs->fidlock);
4779a747e4fSDavid du Colombier 			return f;
4789a747e4fSDavid du Colombier 		}
4799a747e4fSDavid du Colombier 	}
4809a747e4fSDavid du Colombier 	unlock(&fs->fidlock);
4819a747e4fSDavid du Colombier 	return nil;
4829a747e4fSDavid du Colombier }
4839a747e4fSDavid du Colombier 
4849a747e4fSDavid du Colombier void
Exputfid(Export * fs,Fid * f)4859a747e4fSDavid du Colombier Exputfid(Export *fs, Fid *f)
4869a747e4fSDavid du Colombier {
4879a747e4fSDavid du Colombier 	lock(&fs->fidlock);
4889a747e4fSDavid du Colombier 	f->ref--;
4899a747e4fSDavid du Colombier 	if(f->ref == 0 && f->attached == 0){
4909a747e4fSDavid du Colombier 		if(f->chan != nil)
4919a747e4fSDavid du Colombier 			cclose(f->chan);
4929a747e4fSDavid du Colombier 		f->chan = nil;
4939a747e4fSDavid du Colombier 		*f->last = f->next;
4949a747e4fSDavid du Colombier 		if(f->next != nil)
4959a747e4fSDavid du Colombier 			f->next->last = f->last;
4969a747e4fSDavid du Colombier 		unlock(&fs->fidlock);
4979a747e4fSDavid du Colombier 		free(f);
4989a747e4fSDavid du Colombier 		return;
4999a747e4fSDavid du Colombier 	}
5009a747e4fSDavid du Colombier 	unlock(&fs->fidlock);
5019a747e4fSDavid du Colombier }
5029a747e4fSDavid du Colombier 
5039a747e4fSDavid du Colombier static char*
Exversion(Export * fs,Fcall * rpc,uchar *)5049a747e4fSDavid du Colombier Exversion(Export *fs, Fcall *rpc, uchar *)
5059a747e4fSDavid du Colombier {
5069a747e4fSDavid du Colombier 	if(rpc->msize > Maxrpc)
5079a747e4fSDavid du Colombier 		rpc->msize = Maxrpc;
5089a747e4fSDavid du Colombier 	if(strncmp(rpc->version, "9P", 2) != 0){
5099a747e4fSDavid du Colombier 		rpc->version = "unknown";
5109a747e4fSDavid du Colombier 		return nil;
5119a747e4fSDavid du Colombier 	}
5129a747e4fSDavid du Colombier 
5139a747e4fSDavid du Colombier 	fs->iounit = rpc->msize - IOHDRSZ;
5149a747e4fSDavid du Colombier 	rpc->version = "9P2000";
5159a747e4fSDavid du Colombier 	return nil;
5169a747e4fSDavid du Colombier }
5179a747e4fSDavid du Colombier 
5189a747e4fSDavid du Colombier static char*
Exauth(Export *,Fcall *,uchar *)5199a747e4fSDavid du Colombier Exauth(Export *, Fcall *, uchar *)
5209a747e4fSDavid du Colombier {
5219a747e4fSDavid du Colombier 	return "vnc: authentication not required";
5229a747e4fSDavid du Colombier }
5239a747e4fSDavid du Colombier 
5249a747e4fSDavid du Colombier static char*
Exattach(Export * fs,Fcall * rpc,uchar *)5259a747e4fSDavid du Colombier Exattach(Export *fs, Fcall *rpc, uchar *)
5269a747e4fSDavid du Colombier {
5279a747e4fSDavid du Colombier 	Fid *f;
5289a747e4fSDavid du Colombier 	int w;
5299a747e4fSDavid du Colombier 
5309a747e4fSDavid du Colombier 	w = 0;
5319a747e4fSDavid du Colombier 	if(rpc->aname != nil)
5329a747e4fSDavid du Colombier 		w = strtol(rpc->aname, nil, 10);
5339a747e4fSDavid du Colombier 	if(w < 0 || w > fs->nroots)
5349a747e4fSDavid du Colombier 		error(Ebadspec);
5359a747e4fSDavid du Colombier 	f = Exmkfid(fs, rpc->fid);
5369a747e4fSDavid du Colombier 	if(f == nil)
5379a747e4fSDavid du Colombier 		return Einuse;
5389a747e4fSDavid du Colombier 	if(waserror()){
5399a747e4fSDavid du Colombier 		f->attached = 0;
5409a747e4fSDavid du Colombier 		Exputfid(fs, f);
5419a747e4fSDavid du Colombier 		return up->error;
5429a747e4fSDavid du Colombier 	}
5439a747e4fSDavid du Colombier 	f->chan = cclone(fs->roots[w]);
5449a747e4fSDavid du Colombier 	poperror();
5459a747e4fSDavid du Colombier 	rpc->qid = f->chan->qid;
5469a747e4fSDavid du Colombier 	Exputfid(fs, f);
5479a747e4fSDavid du Colombier 	return nil;
5489a747e4fSDavid du Colombier }
5499a747e4fSDavid du Colombier 
5509a747e4fSDavid du Colombier static char*
Exclunk(Export * fs,Fcall * rpc,uchar *)5519a747e4fSDavid du Colombier Exclunk(Export *fs, Fcall *rpc, uchar *)
5529a747e4fSDavid du Colombier {
5539a747e4fSDavid du Colombier 	Fid *f;
5549a747e4fSDavid du Colombier 
5559a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
5569a747e4fSDavid du Colombier 	if(f != nil){
5579a747e4fSDavid du Colombier 		f->attached = 0;
5589a747e4fSDavid du Colombier 		Exputfid(fs, f);
5599a747e4fSDavid du Colombier 	}
5609a747e4fSDavid du Colombier 	return nil;
5619a747e4fSDavid du Colombier }
5629a747e4fSDavid du Colombier 
5639a747e4fSDavid du Colombier static char*
Exwalk(Export * fs,Fcall * rpc,uchar *)5649a747e4fSDavid du Colombier Exwalk(Export *fs, Fcall *rpc, uchar *)
5659a747e4fSDavid du Colombier {
5669a747e4fSDavid du Colombier 	Fid *volatile f, *volatile nf;
5679a747e4fSDavid du Colombier 	Walkqid *wq;
5689a747e4fSDavid du Colombier 	Chan *c;
5699a747e4fSDavid du Colombier 	int i, nwname;
5709a747e4fSDavid du Colombier 	int volatile isnew;
5719a747e4fSDavid du Colombier 
5729a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
5739a747e4fSDavid du Colombier 	if(f == nil)
5749a747e4fSDavid du Colombier 		return Enofid;
5759a747e4fSDavid du Colombier 	nf = nil;
5769a747e4fSDavid du Colombier 	if(waserror()){
5779a747e4fSDavid du Colombier 		Exputfid(fs, f);
5789a747e4fSDavid du Colombier 		if(nf != nil)
5799a747e4fSDavid du Colombier 			Exputfid(fs, nf);
5809a747e4fSDavid du Colombier 		return up->error;
5819a747e4fSDavid du Colombier 	}
5829a747e4fSDavid du Colombier 
5839a747e4fSDavid du Colombier 	/*
5849a747e4fSDavid du Colombier 	 * optional clone, but don't attach it until the walk succeeds.
5859a747e4fSDavid du Colombier 	 */
5869a747e4fSDavid du Colombier 	if(rpc->fid != rpc->newfid){
5879a747e4fSDavid du Colombier 		nf = Exmkfid(fs, rpc->newfid);
5889a747e4fSDavid du Colombier 		if(nf == nil)
5899a747e4fSDavid du Colombier 			error(Einuse);
5909a747e4fSDavid du Colombier 		nf->attached = 0;
5919a747e4fSDavid du Colombier 		isnew = 1;
5929a747e4fSDavid du Colombier 	}else{
5939a747e4fSDavid du Colombier 		nf = Exgetfid(fs, rpc->fid);
5949a747e4fSDavid du Colombier 		isnew = 0;
5959a747e4fSDavid du Colombier 	}
5969a747e4fSDavid du Colombier 
5979a747e4fSDavid du Colombier 	/*
5989a747e4fSDavid du Colombier 	 * let the device do the work
5999a747e4fSDavid du Colombier 	 */
6009a747e4fSDavid du Colombier 	c = f->chan;
6019a747e4fSDavid du Colombier 	nwname = rpc->nwname;
6029a747e4fSDavid du Colombier 	wq = (*devtab[c->type]->walk)(c, nf->chan, rpc->wname, nwname);
6039a747e4fSDavid du Colombier 	if(wq == nil)
6049a747e4fSDavid du Colombier 		error(Enonexist);
6059a747e4fSDavid du Colombier 
6069a747e4fSDavid du Colombier 	poperror();
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier 	/*
6099a747e4fSDavid du Colombier 	 * copy qid array
6109a747e4fSDavid du Colombier 	 */
6119a747e4fSDavid du Colombier 	for(i = 0; i < wq->nqid; i++)
6129a747e4fSDavid du Colombier 		rpc->wqid[i] = wq->qid[i];
6139a747e4fSDavid du Colombier 	rpc->nwqid = wq->nqid;
6149a747e4fSDavid du Colombier 
6159a747e4fSDavid du Colombier 	/*
6169a747e4fSDavid du Colombier 	 * update the channel if everything walked correctly.
6179a747e4fSDavid du Colombier 	 */
6189a747e4fSDavid du Colombier 	if(isnew && wq->nqid == nwname){
6199a747e4fSDavid du Colombier 		nf->chan = wq->clone;
6209a747e4fSDavid du Colombier 		nf->attached = 1;
6219a747e4fSDavid du Colombier 	}
6229a747e4fSDavid du Colombier 
6239a747e4fSDavid du Colombier 	free(wq);
6249a747e4fSDavid du Colombier 	Exputfid(fs, f);
6259a747e4fSDavid du Colombier 	Exputfid(fs, nf);
6269a747e4fSDavid du Colombier 	return nil;
6279a747e4fSDavid du Colombier }
6289a747e4fSDavid du Colombier 
6299a747e4fSDavid du Colombier static char*
Exopen(Export * fs,Fcall * rpc,uchar *)6309a747e4fSDavid du Colombier Exopen(Export *fs, Fcall *rpc, uchar *)
6319a747e4fSDavid du Colombier {
6329a747e4fSDavid du Colombier 	Fid *volatile f;
6339a747e4fSDavid du Colombier 	Chan *c;
6349a747e4fSDavid du Colombier 	int iou;
6359a747e4fSDavid du Colombier 
6369a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
6379a747e4fSDavid du Colombier 	if(f == nil)
6389a747e4fSDavid du Colombier 		return Enofid;
6399a747e4fSDavid du Colombier 	if(waserror()){
6409a747e4fSDavid du Colombier 		Exputfid(fs, f);
6419a747e4fSDavid du Colombier 		return up->error;
6429a747e4fSDavid du Colombier 	}
6439a747e4fSDavid du Colombier 	c = f->chan;
6449a747e4fSDavid du Colombier 	c = (*devtab[c->type]->open)(c, rpc->mode);
6459a747e4fSDavid du Colombier 	poperror();
6469a747e4fSDavid du Colombier 
6479a747e4fSDavid du Colombier 	f->chan = c;
6489a747e4fSDavid du Colombier 	f->offset = 0;
6499a747e4fSDavid du Colombier 	rpc->qid = f->chan->qid;
6509a747e4fSDavid du Colombier 	iou = f->chan->iounit;
6519a747e4fSDavid du Colombier 	if(iou > fs->iounit)
6529a747e4fSDavid du Colombier 		iou = fs->iounit;
6539a747e4fSDavid du Colombier 	rpc->iounit = iou;
6549a747e4fSDavid du Colombier 	Exputfid(fs, f);
6559a747e4fSDavid du Colombier 	return nil;
6569a747e4fSDavid du Colombier }
6579a747e4fSDavid du Colombier 
6589a747e4fSDavid du Colombier static char*
Excreate(Export * fs,Fcall * rpc,uchar *)6599a747e4fSDavid du Colombier Excreate(Export *fs, Fcall *rpc, uchar *)
6609a747e4fSDavid du Colombier {
6619a747e4fSDavid du Colombier 	Fid *f;
6629a747e4fSDavid du Colombier 	Chan *c;
6639a747e4fSDavid du Colombier 	int iou;
6649a747e4fSDavid du Colombier 
6659a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
6669a747e4fSDavid du Colombier 	if(f == nil)
6679a747e4fSDavid du Colombier 		return Enofid;
6689a747e4fSDavid du Colombier 	if(waserror()){
6699a747e4fSDavid du Colombier 		Exputfid(fs, f);
6709a747e4fSDavid du Colombier 		return up->error;
6719a747e4fSDavid du Colombier 	}
6729a747e4fSDavid du Colombier 	c = f->chan;
6739a747e4fSDavid du Colombier 	(*devtab[c->type]->create)(c, rpc->name, rpc->mode, rpc->perm);
6749a747e4fSDavid du Colombier 	poperror();
6759a747e4fSDavid du Colombier 
6769a747e4fSDavid du Colombier 	f->chan = c;
6779a747e4fSDavid du Colombier 	rpc->qid = f->chan->qid;
6789a747e4fSDavid du Colombier 	iou = f->chan->iounit;
6799a747e4fSDavid du Colombier 	if(iou > fs->iounit)
6809a747e4fSDavid du Colombier 		iou = fs->iounit;
6819a747e4fSDavid du Colombier 	rpc->iounit = iou;
6829a747e4fSDavid du Colombier 	Exputfid(fs, f);
6839a747e4fSDavid du Colombier 	return nil;
6849a747e4fSDavid du Colombier }
6859a747e4fSDavid du Colombier 
6869a747e4fSDavid du Colombier static char*
Exread(Export * fs,Fcall * rpc,uchar * buf)6879a747e4fSDavid du Colombier Exread(Export *fs, Fcall *rpc, uchar *buf)
6889a747e4fSDavid du Colombier {
6899a747e4fSDavid du Colombier 	Fid *f;
6909a747e4fSDavid du Colombier 	Chan *c;
6919a747e4fSDavid du Colombier 	long off;
6929a747e4fSDavid du Colombier 
6939a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
6949a747e4fSDavid du Colombier 	if(f == nil)
6959a747e4fSDavid du Colombier 		return Enofid;
6969a747e4fSDavid du Colombier 
6979a747e4fSDavid du Colombier 	c = f->chan;
6989a747e4fSDavid du Colombier 
6999a747e4fSDavid du Colombier 	if(waserror()){
7009a747e4fSDavid du Colombier 		Exputfid(fs, f);
7019a747e4fSDavid du Colombier 		return up->error;
7029a747e4fSDavid du Colombier 	}
7039a747e4fSDavid du Colombier 
7049a747e4fSDavid du Colombier 	rpc->data = (char*)buf;
7059a747e4fSDavid du Colombier 	off = rpc->offset;
7069a747e4fSDavid du Colombier 	c->offset = off;
7079a747e4fSDavid du Colombier 	rpc->count = (*devtab[c->type]->read)(c, rpc->data, rpc->count, off);
7089a747e4fSDavid du Colombier 	poperror();
7099a747e4fSDavid du Colombier 	Exputfid(fs, f);
7109a747e4fSDavid du Colombier 	return nil;
7119a747e4fSDavid du Colombier }
7129a747e4fSDavid du Colombier 
7139a747e4fSDavid du Colombier static char*
Exwrite(Export * fs,Fcall * rpc,uchar *)7149a747e4fSDavid du Colombier Exwrite(Export *fs, Fcall *rpc, uchar *)
7159a747e4fSDavid du Colombier {
7169a747e4fSDavid du Colombier 	Fid *f;
7179a747e4fSDavid du Colombier 	Chan *c;
7189a747e4fSDavid du Colombier 
7199a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
7209a747e4fSDavid du Colombier 	if(f == nil)
7219a747e4fSDavid du Colombier 		return Enofid;
7229a747e4fSDavid du Colombier 	if(waserror()){
7239a747e4fSDavid du Colombier 		Exputfid(fs, f);
7249a747e4fSDavid du Colombier 		return up->error;
7259a747e4fSDavid du Colombier 	}
7269a747e4fSDavid du Colombier 	c = f->chan;
7279a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
7289a747e4fSDavid du Colombier 		error(Eisdir);
7299a747e4fSDavid du Colombier 	rpc->count = (*devtab[c->type]->write)(c, rpc->data, rpc->count, rpc->offset);
7309a747e4fSDavid du Colombier 	poperror();
7319a747e4fSDavid du Colombier 	Exputfid(fs, f);
7329a747e4fSDavid du Colombier 	return nil;
7339a747e4fSDavid du Colombier }
7349a747e4fSDavid du Colombier 
7359a747e4fSDavid du Colombier static char*
Exstat(Export * fs,Fcall * rpc,uchar * buf)7369a747e4fSDavid du Colombier Exstat(Export *fs, Fcall *rpc, uchar *buf)
7379a747e4fSDavid du Colombier {
7389a747e4fSDavid du Colombier 	Fid *f;
7399a747e4fSDavid du Colombier 	Chan *c;
7409a747e4fSDavid du Colombier 
7419a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
7429a747e4fSDavid du Colombier 	if(f == nil)
7439a747e4fSDavid du Colombier 		return Enofid;
7449a747e4fSDavid du Colombier 	if(waserror()){
7459a747e4fSDavid du Colombier 		Exputfid(fs, f);
7469a747e4fSDavid du Colombier 		return up->error;
7479a747e4fSDavid du Colombier 	}
7489a747e4fSDavid du Colombier 	c = f->chan;
7499a747e4fSDavid du Colombier 	rpc->stat = buf;
7509a747e4fSDavid du Colombier 	rpc->nstat = (*devtab[c->type]->stat)(c, rpc->stat, Maxrpc);
7519a747e4fSDavid du Colombier 	poperror();
7529a747e4fSDavid du Colombier 	Exputfid(fs, f);
7539a747e4fSDavid du Colombier 	return nil;
7549a747e4fSDavid du Colombier }
7559a747e4fSDavid du Colombier 
7569a747e4fSDavid du Colombier static char*
Exwstat(Export * fs,Fcall * rpc,uchar *)7579a747e4fSDavid du Colombier Exwstat(Export *fs, Fcall *rpc, uchar *)
7589a747e4fSDavid du Colombier {
7599a747e4fSDavid du Colombier 	Fid *f;
7609a747e4fSDavid du Colombier 	Chan *c;
7619a747e4fSDavid du Colombier 
7629a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
7639a747e4fSDavid du Colombier 	if(f == nil)
7649a747e4fSDavid du Colombier 		return Enofid;
7659a747e4fSDavid du Colombier 	if(waserror()){
7669a747e4fSDavid du Colombier 		Exputfid(fs, f);
7679a747e4fSDavid du Colombier 		return up->error;
7689a747e4fSDavid du Colombier 	}
7699a747e4fSDavid du Colombier 	c = f->chan;
7709a747e4fSDavid du Colombier 	(*devtab[c->type]->wstat)(c, rpc->stat, rpc->nstat);
7719a747e4fSDavid du Colombier 	poperror();
7729a747e4fSDavid du Colombier 	Exputfid(fs, f);
7739a747e4fSDavid du Colombier 	return nil;
7749a747e4fSDavid du Colombier }
7759a747e4fSDavid du Colombier 
7769a747e4fSDavid du Colombier static char*
Exremove(Export * fs,Fcall * rpc,uchar *)7779a747e4fSDavid du Colombier Exremove(Export *fs, Fcall *rpc, uchar *)
7789a747e4fSDavid du Colombier {
7799a747e4fSDavid du Colombier 	Fid *f;
7809a747e4fSDavid du Colombier 	Chan *c;
7819a747e4fSDavid du Colombier 
7829a747e4fSDavid du Colombier 	f = Exgetfid(fs, rpc->fid);
7839a747e4fSDavid du Colombier 	if(f == nil)
7849a747e4fSDavid du Colombier 		return Enofid;
7859a747e4fSDavid du Colombier 	if(waserror()){
7869a747e4fSDavid du Colombier 		Exputfid(fs, f);
7879a747e4fSDavid du Colombier 		return up->error;
7889a747e4fSDavid du Colombier 	}
7899a747e4fSDavid du Colombier 	c = f->chan;
7909a747e4fSDavid du Colombier 	(*devtab[c->type]->remove)(c);
7919a747e4fSDavid du Colombier 	poperror();
7929a747e4fSDavid du Colombier 
7939a747e4fSDavid du Colombier 	/*
7949a747e4fSDavid du Colombier 	 * chan is already clunked by remove.
7959a747e4fSDavid du Colombier 	 * however, we need to recover the chan,
7969a747e4fSDavid du Colombier 	 * and follow sysremove's lead in making to point to root.
7979a747e4fSDavid du Colombier 	 */
7989a747e4fSDavid du Colombier 	c->type = 0;
7999a747e4fSDavid du Colombier 
8009a747e4fSDavid du Colombier 	f->attached = 0;
8019a747e4fSDavid du Colombier 	Exputfid(fs, f);
8029a747e4fSDavid du Colombier 	return nil;
8039a747e4fSDavid du Colombier }
804