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