13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "../port/error.h"
73e12c5d1SDavid du Colombier
89a747e4fSDavid du Colombier /*
99a747e4fSDavid du Colombier * References are managed as follows:
109a747e4fSDavid du Colombier * The channel to the server - a network connection or pipe - has one
119a747e4fSDavid du Colombier * reference for every Chan open on the server. The server channel has
129a747e4fSDavid du Colombier * c->mux set to the Mnt used for muxing control to that server. Mnts
139a747e4fSDavid du Colombier * have no reference count; they go away when c goes away.
149a747e4fSDavid du Colombier * Each channel derived from the mount point has mchan set to c,
159a747e4fSDavid du Colombier * and increfs/decrefs mchan to manage references on the server
169a747e4fSDavid du Colombier * connection.
179a747e4fSDavid du Colombier */
189a747e4fSDavid du Colombier
19*ee4c62dfSDavid du Colombier #define MAXRPC (IOHDRSZ+16*1024) /* maybe a larger size will be faster */
20*ee4c62dfSDavid du Colombier /* use a known-good common size for initial negotiation */
21*ee4c62dfSDavid du Colombier #define MAXCMNRPC (IOHDRSZ+8192)
229a747e4fSDavid du Colombier
233e12c5d1SDavid du Colombier struct Mntrpc
243e12c5d1SDavid du Colombier {
257dd7cddfSDavid du Colombier Chan* c; /* Channel for whom we are working */
263e12c5d1SDavid du Colombier Mntrpc* list; /* Free/pending list */
273e12c5d1SDavid du Colombier Fcall request; /* Outgoing file system protocol message */
283e12c5d1SDavid du Colombier Fcall reply; /* Incoming reply */
293e12c5d1SDavid du Colombier Mnt* m; /* Mount device during rpc */
303e12c5d1SDavid du Colombier Rendez r; /* Place to hang out */
319a747e4fSDavid du Colombier uchar* rpc; /* I/O Data buffer */
329a747e4fSDavid du Colombier uint rpclen; /* len of buffer */
339a747e4fSDavid du Colombier Block *b; /* reply blocks */
343e12c5d1SDavid du Colombier char done; /* Rpc completed */
357dd7cddfSDavid du Colombier uvlong stime; /* start time for mnt statistics */
367dd7cddfSDavid du Colombier ulong reqlen; /* request length for mnt statistics */
377dd7cddfSDavid du Colombier ulong replen; /* reply length for mnt statistics */
387dd7cddfSDavid du Colombier Mntrpc* flushed; /* message this one flushes */
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier
41d9306527SDavid du Colombier enum
42d9306527SDavid du Colombier {
43d9306527SDavid du Colombier TAGSHIFT = 5, /* ulong has to be 32 bits */
44d9306527SDavid du Colombier TAGMASK = (1<<TAGSHIFT)-1,
45d9306527SDavid du Colombier NMASK = (64*1024)>>TAGSHIFT,
46d9306527SDavid du Colombier };
47d9306527SDavid du Colombier
483e12c5d1SDavid du Colombier struct Mntalloc
493e12c5d1SDavid du Colombier {
503e12c5d1SDavid du Colombier Lock;
517dd7cddfSDavid du Colombier Mnt* list; /* Mount devices in use */
523e12c5d1SDavid du Colombier Mnt* mntfree; /* Free list */
533e12c5d1SDavid du Colombier Mntrpc* rpcfree;
547dd7cddfSDavid du Colombier int nrpcfree;
557dd7cddfSDavid du Colombier int nrpcused;
567dd7cddfSDavid du Colombier ulong id;
57d9306527SDavid du Colombier ulong tagmask[NMASK];
583e12c5d1SDavid du Colombier }mntalloc;
593e12c5d1SDavid du Colombier
603e12c5d1SDavid du Colombier Mnt* mntchk(Chan*);
613e12c5d1SDavid du Colombier void mntdirfix(uchar*, Chan*);
629a747e4fSDavid du Colombier Mntrpc* mntflushalloc(Mntrpc*, ulong);
637dd7cddfSDavid du Colombier void mntflushfree(Mnt*, Mntrpc*);
643e12c5d1SDavid du Colombier void mntfree(Mntrpc*);
653e12c5d1SDavid du Colombier void mntgate(Mnt*);
663e12c5d1SDavid du Colombier void mntpntfree(Mnt*);
673e12c5d1SDavid du Colombier void mntqrm(Mnt*, Mntrpc*);
689a747e4fSDavid du Colombier Mntrpc* mntralloc(Chan*, ulong);
697dd7cddfSDavid du Colombier long mntrdwr(int, Chan*, void*, long, vlong);
709a747e4fSDavid du Colombier int mntrpcread(Mnt*, Mntrpc*);
713e12c5d1SDavid du Colombier void mountio(Mnt*, Mntrpc*);
723e12c5d1SDavid du Colombier void mountmux(Mnt*, Mntrpc*);
733e12c5d1SDavid du Colombier void mountrpc(Mnt*, Mntrpc*);
747dd7cddfSDavid du Colombier int rpcattn(void*);
757dd7cddfSDavid du Colombier Chan* mntchan(void);
76219b2ee8SDavid du Colombier
779a747e4fSDavid du Colombier char Esbadstat[] = "invalid directory entry received from server";
789a747e4fSDavid du Colombier char Enoversion[] = "version not established for mount channel";
799a747e4fSDavid du Colombier
803e12c5d1SDavid du Colombier
81d9306527SDavid du Colombier void (*mntstats)(int, Chan*, uvlong, ulong);
823e12c5d1SDavid du Colombier
837dd7cddfSDavid du Colombier static void
mntreset(void)843e12c5d1SDavid du Colombier mntreset(void)
853e12c5d1SDavid du Colombier {
863e12c5d1SDavid du Colombier mntalloc.id = 1;
87d9306527SDavid du Colombier mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
88d9306527SDavid du Colombier mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
899a747e4fSDavid du Colombier fmtinstall('F', fcallfmt);
909a747e4fSDavid du Colombier fmtinstall('D', dirfmt);
91d9306527SDavid du Colombier /* We can't install %M since eipfmt does and is used in the kernel [sape] */
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier cinit();
943e12c5d1SDavid du Colombier }
953e12c5d1SDavid du Colombier
969a747e4fSDavid du Colombier /*
979a747e4fSDavid du Colombier * Version is not multiplexed: message sent only once per connection.
989a747e4fSDavid du Colombier */
999a747e4fSDavid du Colombier long
mntversion(Chan * c,char * version,int msize,int returnlen)1009a747e4fSDavid du Colombier mntversion(Chan *c, char *version, int msize, int returnlen)
1013e12c5d1SDavid du Colombier {
1029a747e4fSDavid du Colombier Fcall f;
1039a747e4fSDavid du Colombier uchar *msg;
1043e12c5d1SDavid du Colombier Mnt *m;
1059a747e4fSDavid du Colombier char *v;
1069a747e4fSDavid du Colombier long k, l;
1079a747e4fSDavid du Colombier uvlong oo;
1089a747e4fSDavid du Colombier char buf[128];
1093e12c5d1SDavid du Colombier
1109a747e4fSDavid du Colombier qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
1117dd7cddfSDavid du Colombier if(waserror()){
1129a747e4fSDavid du Colombier qunlock(&c->umqlock);
1137dd7cddfSDavid du Colombier nexterror();
1147dd7cddfSDavid du Colombier }
1159a747e4fSDavid du Colombier
1169a747e4fSDavid du Colombier /* defaults */
1179a747e4fSDavid du Colombier if(msize == 0)
1189a747e4fSDavid du Colombier msize = MAXRPC;
1199a747e4fSDavid du Colombier if(msize > c->iounit && c->iounit != 0)
1209a747e4fSDavid du Colombier msize = c->iounit;
1219a747e4fSDavid du Colombier v = version;
1229a747e4fSDavid du Colombier if(v == nil || v[0] == '\0')
1239a747e4fSDavid du Colombier v = VERSION9P;
1249a747e4fSDavid du Colombier
1259a747e4fSDavid du Colombier /* validity */
1269a747e4fSDavid du Colombier if(msize < 0)
1279a747e4fSDavid du Colombier error("bad iounit in version call");
1289a747e4fSDavid du Colombier if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
1299a747e4fSDavid du Colombier error("bad 9P version specification");
1309a747e4fSDavid du Colombier
1319a747e4fSDavid du Colombier m = c->mux;
1329a747e4fSDavid du Colombier
1339a747e4fSDavid du Colombier if(m != nil){
1349a747e4fSDavid du Colombier qunlock(&c->umqlock);
1357dd7cddfSDavid du Colombier poperror();
1369a747e4fSDavid du Colombier
1379a747e4fSDavid du Colombier strecpy(buf, buf+sizeof buf, m->version);
1389a747e4fSDavid du Colombier k = strlen(buf);
1399a747e4fSDavid du Colombier if(strncmp(buf, v, k) != 0){
1409a747e4fSDavid du Colombier snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
1419a747e4fSDavid du Colombier error(buf);
1423e12c5d1SDavid du Colombier }
1439a747e4fSDavid du Colombier if(returnlen > 0){
1449a747e4fSDavid du Colombier if(returnlen < k)
1459a747e4fSDavid du Colombier error(Eshort);
1469a747e4fSDavid du Colombier memmove(version, buf, k);
1473e12c5d1SDavid du Colombier }
1489a747e4fSDavid du Colombier return k;
1493e12c5d1SDavid du Colombier }
150219b2ee8SDavid du Colombier
1519a747e4fSDavid du Colombier f.type = Tversion;
1529a747e4fSDavid du Colombier f.tag = NOTAG;
1539a747e4fSDavid du Colombier f.msize = msize;
1549a747e4fSDavid du Colombier f.version = v;
155*ee4c62dfSDavid du Colombier msg = malloc(MAXCMNRPC);
1569a747e4fSDavid du Colombier if(msg == nil)
1579a747e4fSDavid du Colombier exhausted("version memory");
1589a747e4fSDavid du Colombier if(waserror()){
1599a747e4fSDavid du Colombier free(msg);
1609a747e4fSDavid du Colombier nexterror();
1619a747e4fSDavid du Colombier }
162*ee4c62dfSDavid du Colombier k = convS2M(&f, msg, MAXCMNRPC);
1639a747e4fSDavid du Colombier if(k == 0)
1649a747e4fSDavid du Colombier error("bad fversion conversion on send");
1659a747e4fSDavid du Colombier
1669a747e4fSDavid du Colombier lock(c);
1679a747e4fSDavid du Colombier oo = c->offset;
1689a747e4fSDavid du Colombier c->offset += k;
1699a747e4fSDavid du Colombier unlock(c);
1709a747e4fSDavid du Colombier
1719a747e4fSDavid du Colombier l = devtab[c->type]->write(c, msg, k, oo);
1729a747e4fSDavid du Colombier
1739a747e4fSDavid du Colombier if(l < k){
1749a747e4fSDavid du Colombier lock(c);
1759a747e4fSDavid du Colombier c->offset -= k - l;
1769a747e4fSDavid du Colombier unlock(c);
1779a747e4fSDavid du Colombier error("short write in fversion");
1789a747e4fSDavid du Colombier }
1799a747e4fSDavid du Colombier
1809a747e4fSDavid du Colombier /* message sent; receive and decode reply */
181*ee4c62dfSDavid du Colombier k = devtab[c->type]->read(c, msg, MAXCMNRPC, c->offset);
1829a747e4fSDavid du Colombier if(k <= 0)
1839a747e4fSDavid du Colombier error("EOF receiving fversion reply");
1849a747e4fSDavid du Colombier
1859a747e4fSDavid du Colombier lock(c);
1869a747e4fSDavid du Colombier c->offset += k;
1879a747e4fSDavid du Colombier unlock(c);
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier l = convM2S(msg, k, &f);
1909a747e4fSDavid du Colombier if(l != k)
1919a747e4fSDavid du Colombier error("bad fversion conversion on reply");
1929a747e4fSDavid du Colombier if(f.type != Rversion){
1939a747e4fSDavid du Colombier if(f.type == Rerror)
1949a747e4fSDavid du Colombier error(f.ename);
1959a747e4fSDavid du Colombier error("unexpected reply type in fversion");
1969a747e4fSDavid du Colombier }
1979a747e4fSDavid du Colombier if(f.msize > msize)
1989a747e4fSDavid du Colombier error("server tries to increase msize in fversion");
1999a747e4fSDavid du Colombier if(f.msize<256 || f.msize>1024*1024)
2009a747e4fSDavid du Colombier error("nonsense value of msize in fversion");
2015fe11e25SDavid du Colombier k = strlen(f.version);
2025fe11e25SDavid du Colombier if(strncmp(f.version, v, k) != 0)
2039a747e4fSDavid du Colombier error("bad 9P version returned from server");
2049a747e4fSDavid du Colombier
2059a747e4fSDavid du Colombier /* now build Mnt associated with this connection */
2069a747e4fSDavid du Colombier lock(&mntalloc);
2073e12c5d1SDavid du Colombier m = mntalloc.mntfree;
2083e12c5d1SDavid du Colombier if(m != 0)
2093e12c5d1SDavid du Colombier mntalloc.mntfree = m->list;
2103e12c5d1SDavid du Colombier else {
2113e12c5d1SDavid du Colombier m = malloc(sizeof(Mnt));
2123e12c5d1SDavid du Colombier if(m == 0) {
2133e12c5d1SDavid du Colombier unlock(&mntalloc);
2143e12c5d1SDavid du Colombier exhausted("mount devices");
2153e12c5d1SDavid du Colombier }
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier m->list = mntalloc.list;
2183e12c5d1SDavid du Colombier mntalloc.list = m;
2199a747e4fSDavid du Colombier m->version = nil;
2209a747e4fSDavid du Colombier kstrdup(&m->version, f.version);
2213e12c5d1SDavid du Colombier m->id = mntalloc.id++;
2229a747e4fSDavid du Colombier m->q = qopen(10*MAXRPC, 0, nil, nil);
2239a747e4fSDavid du Colombier m->msize = f.msize;
2243e12c5d1SDavid du Colombier unlock(&mntalloc);
2253e12c5d1SDavid du Colombier
2265fe11e25SDavid du Colombier if(returnlen > 0){
2275fe11e25SDavid du Colombier if(returnlen < k)
2285fe11e25SDavid du Colombier error(Eshort);
2295fe11e25SDavid du Colombier memmove(version, f.version, k);
2305fe11e25SDavid du Colombier }
2315fe11e25SDavid du Colombier
2329a747e4fSDavid du Colombier poperror(); /* msg */
2339a747e4fSDavid du Colombier free(msg);
2349a747e4fSDavid du Colombier
2357dd7cddfSDavid du Colombier lock(m);
2363e12c5d1SDavid du Colombier m->queue = 0;
2373e12c5d1SDavid du Colombier m->rip = 0;
2389a747e4fSDavid du Colombier
2399a747e4fSDavid du Colombier c->flag |= CMSG;
2409a747e4fSDavid du Colombier c->mux = m;
2413e12c5d1SDavid du Colombier m->c = c;
2423e12c5d1SDavid du Colombier unlock(m);
2433e12c5d1SDavid du Colombier
2449a747e4fSDavid du Colombier poperror(); /* c */
2459a747e4fSDavid du Colombier qunlock(&c->umqlock);
2469a747e4fSDavid du Colombier
2479a747e4fSDavid du Colombier return k;
2489a747e4fSDavid du Colombier }
2499a747e4fSDavid du Colombier
2509a747e4fSDavid du Colombier Chan*
mntauth(Chan * c,char * spec)2519a747e4fSDavid du Colombier mntauth(Chan *c, char *spec)
2529a747e4fSDavid du Colombier {
2539a747e4fSDavid du Colombier Mnt *m;
2549a747e4fSDavid du Colombier Mntrpc *r;
2559a747e4fSDavid du Colombier
2569a747e4fSDavid du Colombier m = c->mux;
2579a747e4fSDavid du Colombier
2589a747e4fSDavid du Colombier if(m == nil){
2599a747e4fSDavid du Colombier mntversion(c, VERSION9P, MAXRPC, 0);
2609a747e4fSDavid du Colombier m = c->mux;
2619a747e4fSDavid du Colombier if(m == nil)
2629a747e4fSDavid du Colombier error(Enoversion);
2639a747e4fSDavid du Colombier }
2649a747e4fSDavid du Colombier
2657dd7cddfSDavid du Colombier c = mntchan();
2663e12c5d1SDavid du Colombier if(waserror()) {
2677dd7cddfSDavid du Colombier /* Close must not be called since it will
2687dd7cddfSDavid du Colombier * call mnt recursively
269219b2ee8SDavid du Colombier */
2703e12c5d1SDavid du Colombier chanfree(c);
2713e12c5d1SDavid du Colombier nexterror();
2723e12c5d1SDavid du Colombier }
2733e12c5d1SDavid du Colombier
2749a747e4fSDavid du Colombier r = mntralloc(0, m->msize);
2757dd7cddfSDavid du Colombier
2769a747e4fSDavid du Colombier if(waserror()) {
2779a747e4fSDavid du Colombier mntfree(r);
2789a747e4fSDavid du Colombier nexterror();
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier
2819a747e4fSDavid du Colombier r->request.type = Tauth;
2829a747e4fSDavid du Colombier r->request.afid = c->fid;
2839a747e4fSDavid du Colombier r->request.uname = up->user;
2849a747e4fSDavid du Colombier r->request.aname = spec;
2859a747e4fSDavid du Colombier mountrpc(m, r);
2869a747e4fSDavid du Colombier
2879a747e4fSDavid du Colombier c->qid = r->reply.aqid;
2889a747e4fSDavid du Colombier c->mchan = m->c;
2899a747e4fSDavid du Colombier incref(m->c);
2909a747e4fSDavid du Colombier c->mqid = c->qid;
2919a747e4fSDavid du Colombier c->mode = ORDWR;
2929a747e4fSDavid du Colombier
2939a747e4fSDavid du Colombier poperror(); /* r */
2949a747e4fSDavid du Colombier mntfree(r);
2959a747e4fSDavid du Colombier
2969a747e4fSDavid du Colombier poperror(); /* c */
2979a747e4fSDavid du Colombier
2989a747e4fSDavid du Colombier return c;
2999a747e4fSDavid du Colombier
3009a747e4fSDavid du Colombier }
3019a747e4fSDavid du Colombier
3029a747e4fSDavid du Colombier static Chan*
mntattach(char * muxattach)3039a747e4fSDavid du Colombier mntattach(char *muxattach)
3049a747e4fSDavid du Colombier {
3059a747e4fSDavid du Colombier Mnt *m;
3069a747e4fSDavid du Colombier Chan *c;
3079a747e4fSDavid du Colombier Mntrpc *r;
3089a747e4fSDavid du Colombier struct bogus{
3099a747e4fSDavid du Colombier Chan *chan;
3109a747e4fSDavid du Colombier Chan *authchan;
3119a747e4fSDavid du Colombier char *spec;
3129a747e4fSDavid du Colombier int flags;
3139a747e4fSDavid du Colombier }bogus;
3149a747e4fSDavid du Colombier
3159a747e4fSDavid du Colombier bogus = *((struct bogus *)muxattach);
3169a747e4fSDavid du Colombier c = bogus.chan;
3179a747e4fSDavid du Colombier
3189a747e4fSDavid du Colombier m = c->mux;
3199a747e4fSDavid du Colombier
3209a747e4fSDavid du Colombier if(m == nil){
3219a747e4fSDavid du Colombier mntversion(c, nil, 0, 0);
3229a747e4fSDavid du Colombier m = c->mux;
3239a747e4fSDavid du Colombier if(m == nil)
3249a747e4fSDavid du Colombier error(Enoversion);
3259a747e4fSDavid du Colombier }
3269a747e4fSDavid du Colombier
3279a747e4fSDavid du Colombier c = mntchan();
3289a747e4fSDavid du Colombier if(waserror()) {
3299a747e4fSDavid du Colombier /* Close must not be called since it will
3309a747e4fSDavid du Colombier * call mnt recursively
3319a747e4fSDavid du Colombier */
3329a747e4fSDavid du Colombier chanfree(c);
3339a747e4fSDavid du Colombier nexterror();
3349a747e4fSDavid du Colombier }
3359a747e4fSDavid du Colombier
3369a747e4fSDavid du Colombier r = mntralloc(0, m->msize);
3379a747e4fSDavid du Colombier
3389a747e4fSDavid du Colombier if(waserror()) {
3399a747e4fSDavid du Colombier mntfree(r);
3409a747e4fSDavid du Colombier nexterror();
3419a747e4fSDavid du Colombier }
3429a747e4fSDavid du Colombier
3439a747e4fSDavid du Colombier r->request.type = Tattach;
3449a747e4fSDavid du Colombier r->request.fid = c->fid;
3459a747e4fSDavid du Colombier if(bogus.authchan == nil)
3469a747e4fSDavid du Colombier r->request.afid = NOFID;
3479a747e4fSDavid du Colombier else
3489a747e4fSDavid du Colombier r->request.afid = bogus.authchan->fid;
3499a747e4fSDavid du Colombier r->request.uname = up->user;
3509a747e4fSDavid du Colombier r->request.aname = bogus.spec;
3519a747e4fSDavid du Colombier mountrpc(m, r);
3529a747e4fSDavid du Colombier
3539a747e4fSDavid du Colombier c->qid = r->reply.qid;
3549a747e4fSDavid du Colombier c->mchan = m->c;
3559a747e4fSDavid du Colombier incref(m->c);
3569a747e4fSDavid du Colombier c->mqid = c->qid;
3579a747e4fSDavid du Colombier
3589a747e4fSDavid du Colombier poperror(); /* r */
3599a747e4fSDavid du Colombier mntfree(r);
3609a747e4fSDavid du Colombier
3619a747e4fSDavid du Colombier poperror(); /* c */
3629a747e4fSDavid du Colombier
3637dd7cddfSDavid du Colombier if(bogus.flags&MCACHE)
3647dd7cddfSDavid du Colombier c->flag |= CCACHE;
3657dd7cddfSDavid du Colombier return c;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier Chan*
mntchan(void)3697dd7cddfSDavid du Colombier mntchan(void)
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier Chan *c;
3727dd7cddfSDavid du Colombier
3737dd7cddfSDavid du Colombier c = devattach('M', 0);
3747dd7cddfSDavid du Colombier lock(&mntalloc);
3757dd7cddfSDavid du Colombier c->dev = mntalloc.id++;
3767dd7cddfSDavid du Colombier unlock(&mntalloc);
3777dd7cddfSDavid du Colombier
3789a747e4fSDavid du Colombier if(c->mchan)
3799a747e4fSDavid du Colombier panic("mntchan non-zero %p", c->mchan);
3807dd7cddfSDavid du Colombier return c;
3817dd7cddfSDavid du Colombier }
3827dd7cddfSDavid du Colombier
3839a747e4fSDavid du Colombier static Walkqid*
mntwalk(Chan * c,Chan * nc,char ** name,int nname)3849a747e4fSDavid du Colombier mntwalk(Chan *c, Chan *nc, char **name, int nname)
3857dd7cddfSDavid du Colombier {
3869a747e4fSDavid du Colombier int i, alloc;
3873e12c5d1SDavid du Colombier Mnt *m;
3883e12c5d1SDavid du Colombier Mntrpc *r;
3899a747e4fSDavid du Colombier Walkqid *wq;
3903e12c5d1SDavid du Colombier
3919a747e4fSDavid du Colombier if(nc != nil)
3929a747e4fSDavid du Colombier print("mntwalk: nc != nil\n");
3939a747e4fSDavid du Colombier if(nname > MAXWELEM)
3949a747e4fSDavid du Colombier error("devmnt: too many name elements");
3959a747e4fSDavid du Colombier alloc = 0;
3969a747e4fSDavid du Colombier wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
3979a747e4fSDavid du Colombier if(waserror()){
3989a747e4fSDavid du Colombier if(alloc && wq->clone!=nil)
3999a747e4fSDavid du Colombier cclose(wq->clone);
4009a747e4fSDavid du Colombier free(wq);
4019a747e4fSDavid du Colombier return nil;
4029a747e4fSDavid du Colombier }
4039a747e4fSDavid du Colombier
4049a747e4fSDavid du Colombier alloc = 0;
4053e12c5d1SDavid du Colombier m = mntchk(c);
4069a747e4fSDavid du Colombier r = mntralloc(c, m->msize);
4079a747e4fSDavid du Colombier if(nc == nil){
4089a747e4fSDavid du Colombier nc = devclone(c);
4099a747e4fSDavid du Colombier /*
4109a747e4fSDavid du Colombier * Until the other side accepts this fid, we can't mntclose it.
4119a747e4fSDavid du Colombier * Therefore set type to 0 for now; rootclose is known to be safe.
4129a747e4fSDavid du Colombier */
4139a747e4fSDavid du Colombier nc->type = 0;
4143e12c5d1SDavid du Colombier alloc = 1;
4153e12c5d1SDavid du Colombier }
4169a747e4fSDavid du Colombier wq->clone = nc;
4176bbfed0dSDavid du Colombier nc->flag |= c->flag&CCACHE;
4189a747e4fSDavid du Colombier
4193e12c5d1SDavid du Colombier if(waserror()) {
4203e12c5d1SDavid du Colombier mntfree(r);
4213e12c5d1SDavid du Colombier nexterror();
4223e12c5d1SDavid du Colombier }
4233e12c5d1SDavid du Colombier r->request.type = Twalk;
4243e12c5d1SDavid du Colombier r->request.fid = c->fid;
4259a747e4fSDavid du Colombier r->request.newfid = nc->fid;
4269a747e4fSDavid du Colombier r->request.nwname = nname;
4279a747e4fSDavid du Colombier memmove(r->request.wname, name, nname*sizeof(char*));
4289a747e4fSDavid du Colombier
4293e12c5d1SDavid du Colombier mountrpc(m, r);
4303e12c5d1SDavid du Colombier
4319a747e4fSDavid du Colombier if(r->reply.nwqid > nname)
4329a747e4fSDavid du Colombier error("too many QIDs returned by walk");
4339a747e4fSDavid du Colombier if(r->reply.nwqid < nname){
4349a747e4fSDavid du Colombier if(alloc)
4359a747e4fSDavid du Colombier cclose(nc);
4369a747e4fSDavid du Colombier wq->clone = nil;
4379a747e4fSDavid du Colombier if(r->reply.nwqid == 0){
4389a747e4fSDavid du Colombier free(wq);
4399a747e4fSDavid du Colombier wq = nil;
4409a747e4fSDavid du Colombier goto Return;
4419a747e4fSDavid du Colombier }
4423e12c5d1SDavid du Colombier }
4433e12c5d1SDavid du Colombier
4449a747e4fSDavid du Colombier /* move new fid onto mnt device and update its qid */
4459a747e4fSDavid du Colombier if(wq->clone != nil){
4469a747e4fSDavid du Colombier if(wq->clone != c){
4479a747e4fSDavid du Colombier wq->clone->type = c->type;
4489a747e4fSDavid du Colombier wq->clone->mchan = c->mchan;
4499a747e4fSDavid du Colombier incref(c->mchan);
4509a747e4fSDavid du Colombier }
4519a747e4fSDavid du Colombier if(r->reply.nwqid > 0)
4529a747e4fSDavid du Colombier wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
4539a747e4fSDavid du Colombier }
4549a747e4fSDavid du Colombier wq->nqid = r->reply.nwqid;
4559a747e4fSDavid du Colombier for(i=0; i<wq->nqid; i++)
4569a747e4fSDavid du Colombier wq->qid[i] = r->reply.wqid[i];
4579a747e4fSDavid du Colombier
4589a747e4fSDavid du Colombier Return:
4599a747e4fSDavid du Colombier poperror();
4609a747e4fSDavid du Colombier mntfree(r);
4619a747e4fSDavid du Colombier poperror();
4629a747e4fSDavid du Colombier return wq;
4639a747e4fSDavid du Colombier }
4649a747e4fSDavid du Colombier
4659a747e4fSDavid du Colombier static int
mntstat(Chan * c,uchar * dp,int n)4669a747e4fSDavid du Colombier mntstat(Chan *c, uchar *dp, int n)
4673e12c5d1SDavid du Colombier {
4683e12c5d1SDavid du Colombier Mnt *m;
4693e12c5d1SDavid du Colombier Mntrpc *r;
4703e12c5d1SDavid du Colombier
4719a747e4fSDavid du Colombier if(n < BIT16SZ)
4729a747e4fSDavid du Colombier error(Eshortstat);
4733e12c5d1SDavid du Colombier m = mntchk(c);
4749a747e4fSDavid du Colombier r = mntralloc(c, m->msize);
4753e12c5d1SDavid du Colombier if(waserror()) {
4763e12c5d1SDavid du Colombier mntfree(r);
4773e12c5d1SDavid du Colombier nexterror();
4783e12c5d1SDavid du Colombier }
4793e12c5d1SDavid du Colombier r->request.type = Tstat;
4803e12c5d1SDavid du Colombier r->request.fid = c->fid;
4813e12c5d1SDavid du Colombier mountrpc(m, r);
4823e12c5d1SDavid du Colombier
4839a747e4fSDavid du Colombier if(r->reply.nstat > n){
4849a747e4fSDavid du Colombier n = BIT16SZ;
485754a2748SDavid du Colombier PBIT16((uchar*)dp, r->reply.nstat-2);
4869a747e4fSDavid du Colombier }else{
4879a747e4fSDavid du Colombier n = r->reply.nstat;
4889a747e4fSDavid du Colombier memmove(dp, r->reply.stat, n);
4899a747e4fSDavid du Colombier validstat(dp, n);
4909a747e4fSDavid du Colombier mntdirfix(dp, c);
4919a747e4fSDavid du Colombier }
4923e12c5d1SDavid du Colombier poperror();
4933e12c5d1SDavid du Colombier mntfree(r);
4949a747e4fSDavid du Colombier return n;
4953e12c5d1SDavid du Colombier }
4963e12c5d1SDavid du Colombier
4977dd7cddfSDavid du Colombier static Chan*
mntopencreate(int type,Chan * c,char * name,int omode,ulong perm)4989a747e4fSDavid du Colombier mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
4993e12c5d1SDavid du Colombier {
5003e12c5d1SDavid du Colombier Mnt *m;
5013e12c5d1SDavid du Colombier Mntrpc *r;
5023e12c5d1SDavid du Colombier
5033e12c5d1SDavid du Colombier m = mntchk(c);
5049a747e4fSDavid du Colombier r = mntralloc(c, m->msize);
5053e12c5d1SDavid du Colombier if(waserror()) {
5063e12c5d1SDavid du Colombier mntfree(r);
5073e12c5d1SDavid du Colombier nexterror();
5083e12c5d1SDavid du Colombier }
5099a747e4fSDavid du Colombier r->request.type = type;
5103e12c5d1SDavid du Colombier r->request.fid = c->fid;
5113e12c5d1SDavid du Colombier r->request.mode = omode;
5129a747e4fSDavid du Colombier if(type == Tcreate){
5139a747e4fSDavid du Colombier r->request.perm = perm;
5149a747e4fSDavid du Colombier r->request.name = name;
5159a747e4fSDavid du Colombier }
5163e12c5d1SDavid du Colombier mountrpc(m, r);
5173e12c5d1SDavid du Colombier
5183e12c5d1SDavid du Colombier c->qid = r->reply.qid;
5193e12c5d1SDavid du Colombier c->offset = 0;
5203e12c5d1SDavid du Colombier c->mode = openmode(omode);
5219a747e4fSDavid du Colombier c->iounit = r->reply.iounit;
5229a747e4fSDavid du Colombier if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
5239a747e4fSDavid du Colombier c->iounit = m->msize-IOHDRSZ;
5243e12c5d1SDavid du Colombier c->flag |= COPEN;
5253e12c5d1SDavid du Colombier poperror();
5263e12c5d1SDavid du Colombier mntfree(r);
5277dd7cddfSDavid du Colombier
5287dd7cddfSDavid du Colombier if(c->flag & CCACHE)
5297dd7cddfSDavid du Colombier copen(c);
5307dd7cddfSDavid du Colombier
5313e12c5d1SDavid du Colombier return c;
5323e12c5d1SDavid du Colombier }
5333e12c5d1SDavid du Colombier
5349a747e4fSDavid du Colombier static Chan*
mntopen(Chan * c,int omode)5359a747e4fSDavid du Colombier mntopen(Chan *c, int omode)
5369a747e4fSDavid du Colombier {
5379a747e4fSDavid du Colombier return mntopencreate(Topen, c, nil, omode, 0);
5389a747e4fSDavid du Colombier }
5399a747e4fSDavid du Colombier
5407dd7cddfSDavid du Colombier static void
mntcreate(Chan * c,char * name,int omode,ulong perm)5413e12c5d1SDavid du Colombier mntcreate(Chan *c, char *name, int omode, ulong perm)
5423e12c5d1SDavid du Colombier {
5439a747e4fSDavid du Colombier mntopencreate(Tcreate, c, name, omode, perm);
5443e12c5d1SDavid du Colombier }
5453e12c5d1SDavid du Colombier
5467dd7cddfSDavid du Colombier static void
mntclunk(Chan * c,int t)5473e12c5d1SDavid du Colombier mntclunk(Chan *c, int t)
5483e12c5d1SDavid du Colombier {
5493e12c5d1SDavid du Colombier Mnt *m;
5503e12c5d1SDavid du Colombier Mntrpc *r;
5513e12c5d1SDavid du Colombier
5523e12c5d1SDavid du Colombier m = mntchk(c);
5539a747e4fSDavid du Colombier r = mntralloc(c, m->msize);
5543e12c5d1SDavid du Colombier if(waserror()){
5557dd7cddfSDavid du Colombier mntfree(r);
5563e12c5d1SDavid du Colombier nexterror();
5573e12c5d1SDavid du Colombier }
5583e12c5d1SDavid du Colombier
5593e12c5d1SDavid du Colombier r->request.type = t;
5603e12c5d1SDavid du Colombier r->request.fid = c->fid;
5613e12c5d1SDavid du Colombier mountrpc(m, r);
5627dd7cddfSDavid du Colombier mntfree(r);
5633e12c5d1SDavid du Colombier poperror();
5643e12c5d1SDavid du Colombier }
5653e12c5d1SDavid du Colombier
5663e12c5d1SDavid du Colombier void
muxclose(Mnt * m)5679a747e4fSDavid du Colombier muxclose(Mnt *m)
5683e12c5d1SDavid du Colombier {
569219b2ee8SDavid du Colombier Mntrpc *q, *r;
5703e12c5d1SDavid du Colombier
5713e12c5d1SDavid du Colombier for(q = m->queue; q; q = r) {
5723e12c5d1SDavid du Colombier r = q->list;
5733e12c5d1SDavid du Colombier mntfree(q);
5743e12c5d1SDavid du Colombier }
5753e12c5d1SDavid du Colombier m->id = 0;
5769a747e4fSDavid du Colombier free(m->version);
5779a747e4fSDavid du Colombier m->version = nil;
5783e12c5d1SDavid du Colombier mntpntfree(m);
5793e12c5d1SDavid du Colombier }
580219b2ee8SDavid du Colombier
581219b2ee8SDavid du Colombier void
mntpntfree(Mnt * m)5823e12c5d1SDavid du Colombier mntpntfree(Mnt *m)
5833e12c5d1SDavid du Colombier {
5843e12c5d1SDavid du Colombier Mnt *f, **l;
5859a747e4fSDavid du Colombier Queue *q;
5863e12c5d1SDavid du Colombier
5873e12c5d1SDavid du Colombier lock(&mntalloc);
5883e12c5d1SDavid du Colombier l = &mntalloc.list;
5893e12c5d1SDavid du Colombier for(f = *l; f; f = f->list) {
5903e12c5d1SDavid du Colombier if(f == m) {
5913e12c5d1SDavid du Colombier *l = m->list;
5923e12c5d1SDavid du Colombier break;
5933e12c5d1SDavid du Colombier }
5943e12c5d1SDavid du Colombier l = &f->list;
5953e12c5d1SDavid du Colombier }
5963e12c5d1SDavid du Colombier m->list = mntalloc.mntfree;
5973e12c5d1SDavid du Colombier mntalloc.mntfree = m;
5989a747e4fSDavid du Colombier q = m->q;
5993e12c5d1SDavid du Colombier unlock(&mntalloc);
6009a747e4fSDavid du Colombier
6019a747e4fSDavid du Colombier qfree(q);
6023e12c5d1SDavid du Colombier }
6033e12c5d1SDavid du Colombier
6047dd7cddfSDavid du Colombier static void
mntclose(Chan * c)6053e12c5d1SDavid du Colombier mntclose(Chan *c)
6063e12c5d1SDavid du Colombier {
6073e12c5d1SDavid du Colombier mntclunk(c, Tclunk);
6083e12c5d1SDavid du Colombier }
6093e12c5d1SDavid du Colombier
6107dd7cddfSDavid du Colombier static void
mntremove(Chan * c)6113e12c5d1SDavid du Colombier mntremove(Chan *c)
6123e12c5d1SDavid du Colombier {
6133e12c5d1SDavid du Colombier mntclunk(c, Tremove);
6143e12c5d1SDavid du Colombier }
6153e12c5d1SDavid du Colombier
6169a747e4fSDavid du Colombier static int
mntwstat(Chan * c,uchar * dp,int n)6179a747e4fSDavid du Colombier mntwstat(Chan *c, uchar *dp, int n)
6183e12c5d1SDavid du Colombier {
6193e12c5d1SDavid du Colombier Mnt *m;
6203e12c5d1SDavid du Colombier Mntrpc *r;
6213e12c5d1SDavid du Colombier
6223e12c5d1SDavid du Colombier m = mntchk(c);
6239a747e4fSDavid du Colombier r = mntralloc(c, m->msize);
6243e12c5d1SDavid du Colombier if(waserror()) {
6253e12c5d1SDavid du Colombier mntfree(r);
6263e12c5d1SDavid du Colombier nexterror();
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier r->request.type = Twstat;
6293e12c5d1SDavid du Colombier r->request.fid = c->fid;
6309a747e4fSDavid du Colombier r->request.nstat = n;
6319a747e4fSDavid du Colombier r->request.stat = dp;
6323e12c5d1SDavid du Colombier mountrpc(m, r);
6333e12c5d1SDavid du Colombier poperror();
6343e12c5d1SDavid du Colombier mntfree(r);
6359a747e4fSDavid du Colombier return n;
6367dd7cddfSDavid du Colombier }
6377dd7cddfSDavid du Colombier
6387dd7cddfSDavid du Colombier static long
mntread(Chan * c,void * buf,long n,vlong off)6397dd7cddfSDavid du Colombier mntread(Chan *c, void *buf, long n, vlong off)
6403e12c5d1SDavid du Colombier {
6413e12c5d1SDavid du Colombier uchar *p, *e;
6429a747e4fSDavid du Colombier int nc, cache, isdir, dirlen;
6433e12c5d1SDavid du Colombier
6447dd7cddfSDavid du Colombier isdir = 0;
6457dd7cddfSDavid du Colombier cache = c->flag & CCACHE;
6469a747e4fSDavid du Colombier if(c->qid.type & QTDIR) {
6477dd7cddfSDavid du Colombier cache = 0;
6487dd7cddfSDavid du Colombier isdir = 1;
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier p = buf;
6527dd7cddfSDavid du Colombier if(cache) {
6537dd7cddfSDavid du Colombier nc = cread(c, buf, n, off);
6547dd7cddfSDavid du Colombier if(nc > 0) {
6557dd7cddfSDavid du Colombier n -= nc;
6567dd7cddfSDavid du Colombier if(n == 0)
6577dd7cddfSDavid du Colombier return nc;
6587dd7cddfSDavid du Colombier p += nc;
6597dd7cddfSDavid du Colombier off += nc;
6607dd7cddfSDavid du Colombier }
6617dd7cddfSDavid du Colombier n = mntrdwr(Tread, c, p, n, off);
6627dd7cddfSDavid du Colombier cupdate(c, p, n, off);
6637dd7cddfSDavid du Colombier return n + nc;
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier
6667dd7cddfSDavid du Colombier n = mntrdwr(Tread, c, buf, n, off);
6677dd7cddfSDavid du Colombier if(isdir) {
6689a747e4fSDavid du Colombier for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
6699a747e4fSDavid du Colombier dirlen = BIT16SZ+GBIT16(p);
6709a747e4fSDavid du Colombier if(p+dirlen > e)
6719a747e4fSDavid du Colombier break;
6729a747e4fSDavid du Colombier validstat(p, dirlen);
6733e12c5d1SDavid du Colombier mntdirfix(p, c);
6747dd7cddfSDavid du Colombier }
6759a747e4fSDavid du Colombier if(p != e)
6769a747e4fSDavid du Colombier error(Esbadstat);
6773e12c5d1SDavid du Colombier }
6789a747e4fSDavid du Colombier return n;
6797dd7cddfSDavid du Colombier }
6807dd7cddfSDavid du Colombier
6817dd7cddfSDavid du Colombier static long
mntwrite(Chan * c,void * buf,long n,vlong off)6827dd7cddfSDavid du Colombier mntwrite(Chan *c, void *buf, long n, vlong off)
6837dd7cddfSDavid du Colombier {
6847dd7cddfSDavid du Colombier return mntrdwr(Twrite, c, buf, n, off);
6853e12c5d1SDavid du Colombier }
6863e12c5d1SDavid du Colombier
6873e12c5d1SDavid du Colombier long
mntrdwr(int type,Chan * c,void * buf,long n,vlong off)6887dd7cddfSDavid du Colombier mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
6897dd7cddfSDavid du Colombier {
6907dd7cddfSDavid du Colombier Mnt *m;
6917dd7cddfSDavid du Colombier Mntrpc *r;
6927dd7cddfSDavid du Colombier char *uba;
6937dd7cddfSDavid du Colombier int cache;
6947dd7cddfSDavid du Colombier ulong cnt, nr, nreq;
6957dd7cddfSDavid du Colombier
6967dd7cddfSDavid du Colombier m = mntchk(c);
6977dd7cddfSDavid du Colombier uba = buf;
6987dd7cddfSDavid du Colombier cnt = 0;
6997dd7cddfSDavid du Colombier cache = c->flag & CCACHE;
7009a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
7017dd7cddfSDavid du Colombier cache = 0;
7027dd7cddfSDavid du Colombier for(;;) {
7039a747e4fSDavid du Colombier r = mntralloc(c, m->msize);
7047dd7cddfSDavid du Colombier if(waserror()) {
7057dd7cddfSDavid du Colombier mntfree(r);
7067dd7cddfSDavid du Colombier nexterror();
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier r->request.type = type;
7097dd7cddfSDavid du Colombier r->request.fid = c->fid;
7107dd7cddfSDavid du Colombier r->request.offset = off;
7117dd7cddfSDavid du Colombier r->request.data = uba;
7129a747e4fSDavid du Colombier nr = n;
7139a747e4fSDavid du Colombier if(nr > m->msize-IOHDRSZ)
7149a747e4fSDavid du Colombier nr = m->msize-IOHDRSZ;
7159a747e4fSDavid du Colombier r->request.count = nr;
7167dd7cddfSDavid du Colombier mountrpc(m, r);
7177dd7cddfSDavid du Colombier nreq = r->request.count;
7187dd7cddfSDavid du Colombier nr = r->reply.count;
7197dd7cddfSDavid du Colombier if(nr > nreq)
7207dd7cddfSDavid du Colombier nr = nreq;
7217dd7cddfSDavid du Colombier
7227dd7cddfSDavid du Colombier if(type == Tread)
7239a747e4fSDavid du Colombier r->b = bl2mem((uchar*)uba, r->b, nr);
7247dd7cddfSDavid du Colombier else if(cache)
7257dd7cddfSDavid du Colombier cwrite(c, (uchar*)uba, nr, off);
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier poperror();
7287dd7cddfSDavid du Colombier mntfree(r);
7297dd7cddfSDavid du Colombier off += nr;
7303e12c5d1SDavid du Colombier uba += nr;
7313e12c5d1SDavid du Colombier cnt += nr;
732219b2ee8SDavid du Colombier n -= nr;
7337dd7cddfSDavid du Colombier if(nr != nreq || n == 0 || up->nnote)
7343e12c5d1SDavid du Colombier break;
7353e12c5d1SDavid du Colombier }
7363e12c5d1SDavid du Colombier return cnt;
7373e12c5d1SDavid du Colombier }
7383e12c5d1SDavid du Colombier
7393e12c5d1SDavid du Colombier void
mountrpc(Mnt * m,Mntrpc * r)7403e12c5d1SDavid du Colombier mountrpc(Mnt *m, Mntrpc *r)
7413e12c5d1SDavid du Colombier {
7429a747e4fSDavid du Colombier char *sn, *cn;
7437dd7cddfSDavid du Colombier int t;
7447dd7cddfSDavid du Colombier
7457dd7cddfSDavid du Colombier r->reply.tag = 0;
7467dd7cddfSDavid du Colombier r->reply.type = Tmax; /* can't ever be a valid message type */
7473e12c5d1SDavid du Colombier
7483e12c5d1SDavid du Colombier mountio(m, r);
7497dd7cddfSDavid du Colombier
7507dd7cddfSDavid du Colombier t = r->reply.type;
7517dd7cddfSDavid du Colombier switch(t) {
7527dd7cddfSDavid du Colombier case Rerror:
7533e12c5d1SDavid du Colombier error(r->reply.ename);
7547dd7cddfSDavid du Colombier case Rflush:
7553e12c5d1SDavid du Colombier error(Eintr);
7567dd7cddfSDavid du Colombier default:
7577dd7cddfSDavid du Colombier if(t == r->request.type+1)
7587dd7cddfSDavid du Colombier break;
7599a747e4fSDavid du Colombier sn = "?";
7604afe124fSDavid du Colombier if(m->c->path != nil)
7614afe124fSDavid du Colombier sn = m->c->path->s;
7629a747e4fSDavid du Colombier cn = "?";
7634afe124fSDavid du Colombier if(r->c != nil && r->c->path != nil)
7644afe124fSDavid du Colombier cn = r->c->path->s;
765567483c8SDavid du Colombier print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
7669a747e4fSDavid du Colombier up->text, up->pid, sn, cn,
7679a747e4fSDavid du Colombier r, r->request.tag, r->request.fid, r->request.type,
7689a747e4fSDavid du Colombier r->reply.type, r->reply.tag);
7693e12c5d1SDavid du Colombier error(Emountrpc);
7703e12c5d1SDavid du Colombier }
7713e12c5d1SDavid du Colombier }
7723e12c5d1SDavid du Colombier
7733e12c5d1SDavid du Colombier void
mountio(Mnt * m,Mntrpc * r)7743e12c5d1SDavid du Colombier mountio(Mnt *m, Mntrpc *r)
7753e12c5d1SDavid du Colombier {
7763e12c5d1SDavid du Colombier int n;
7773e12c5d1SDavid du Colombier
7787dd7cddfSDavid du Colombier while(waserror()) {
7797dd7cddfSDavid du Colombier if(m->rip == up)
7807dd7cddfSDavid du Colombier mntgate(m);
7819a747e4fSDavid du Colombier if(strcmp(up->errstr, Eintr) != 0){
7827dd7cddfSDavid du Colombier mntflushfree(m, r);
7837dd7cddfSDavid du Colombier nexterror();
7847dd7cddfSDavid du Colombier }
7859a747e4fSDavid du Colombier r = mntflushalloc(r, m->msize);
7867dd7cddfSDavid du Colombier }
7877dd7cddfSDavid du Colombier
7883e12c5d1SDavid du Colombier lock(m);
7893e12c5d1SDavid du Colombier r->m = m;
7903e12c5d1SDavid du Colombier r->list = m->queue;
7913e12c5d1SDavid du Colombier m->queue = r;
7923e12c5d1SDavid du Colombier unlock(m);
7933e12c5d1SDavid du Colombier
7943e12c5d1SDavid du Colombier /* Transmit a file system rpc */
7959a747e4fSDavid du Colombier if(m->msize == 0)
7969a747e4fSDavid du Colombier panic("msize");
7979a747e4fSDavid du Colombier n = convS2M(&r->request, r->rpc, m->msize);
7987dd7cddfSDavid du Colombier if(n < 0)
7997dd7cddfSDavid du Colombier panic("bad message type in mountio");
8007dd7cddfSDavid du Colombier if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
8017dd7cddfSDavid du Colombier error(Emountrpc);
8027dd7cddfSDavid du Colombier r->stime = fastticks(nil);
8037dd7cddfSDavid du Colombier r->reqlen = n;
8043e12c5d1SDavid du Colombier
8053e12c5d1SDavid du Colombier /* Gate readers onto the mount point one at a time */
8063e12c5d1SDavid du Colombier for(;;) {
8073e12c5d1SDavid du Colombier lock(m);
8083e12c5d1SDavid du Colombier if(m->rip == 0)
8093e12c5d1SDavid du Colombier break;
8103e12c5d1SDavid du Colombier unlock(m);
8113e12c5d1SDavid du Colombier sleep(&r->r, rpcattn, r);
8127dd7cddfSDavid du Colombier if(r->done){
8133e12c5d1SDavid du Colombier poperror();
8147dd7cddfSDavid du Colombier mntflushfree(m, r);
8153e12c5d1SDavid du Colombier return;
8163e12c5d1SDavid du Colombier }
8177dd7cddfSDavid du Colombier }
8187dd7cddfSDavid du Colombier m->rip = up;
8193e12c5d1SDavid du Colombier unlock(m);
8203e12c5d1SDavid du Colombier while(r->done == 0) {
8219a747e4fSDavid du Colombier if(mntrpcread(m, r) < 0)
8229a747e4fSDavid du Colombier error(Emountrpc);
8233e12c5d1SDavid du Colombier mountmux(m, r);
8243e12c5d1SDavid du Colombier }
8253e12c5d1SDavid du Colombier mntgate(m);
8267dd7cddfSDavid du Colombier poperror();
8277dd7cddfSDavid du Colombier mntflushfree(m, r);
8283e12c5d1SDavid du Colombier }
8293e12c5d1SDavid du Colombier
8306a9fc400SDavid du Colombier static int
doread(Mnt * m,int len)8316a9fc400SDavid du Colombier doread(Mnt *m, int len)
8326a9fc400SDavid du Colombier {
8336a9fc400SDavid du Colombier Block *b;
8346a9fc400SDavid du Colombier
8356a9fc400SDavid du Colombier while(qlen(m->q) < len){
8366a9fc400SDavid du Colombier b = devtab[m->c->type]->bread(m->c, m->msize, 0);
8376a9fc400SDavid du Colombier if(b == nil)
8386a9fc400SDavid du Colombier return -1;
83918027f8cSDavid du Colombier if(blocklen(b) == 0){
8406a9fc400SDavid du Colombier freeblist(b);
8416a9fc400SDavid du Colombier return -1;
8426a9fc400SDavid du Colombier }
8436a9fc400SDavid du Colombier qaddlist(m->q, b);
8446a9fc400SDavid du Colombier }
8456a9fc400SDavid du Colombier return 0;
8466a9fc400SDavid du Colombier }
8476a9fc400SDavid du Colombier
8489a747e4fSDavid du Colombier int
mntrpcread(Mnt * m,Mntrpc * r)8493e12c5d1SDavid du Colombier mntrpcread(Mnt *m, Mntrpc *r)
8503e12c5d1SDavid du Colombier {
8519a747e4fSDavid du Colombier int i, t, len, hlen;
8529a747e4fSDavid du Colombier Block *b, **l, *nb;
8533e12c5d1SDavid du Colombier
8543e12c5d1SDavid du Colombier r->reply.type = 0;
8553e12c5d1SDavid du Colombier r->reply.tag = 0;
8563e12c5d1SDavid du Colombier
8579a747e4fSDavid du Colombier /* read at least length, type, and tag and pullup to a single block */
8586a9fc400SDavid du Colombier if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
8599a747e4fSDavid du Colombier return -1;
8609a747e4fSDavid du Colombier nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
8619a747e4fSDavid du Colombier
862ed8191acSDavid du Colombier /* read in the rest of the message, avoid ridiculous (for now) message sizes */
8636a9fc400SDavid du Colombier len = GBIT32(nb->rp);
8646a9fc400SDavid du Colombier if(len > m->msize){
8656a9fc400SDavid du Colombier qdiscard(m->q, qlen(m->q));
8669a747e4fSDavid du Colombier return -1;
8679a747e4fSDavid du Colombier }
8686a9fc400SDavid du Colombier if(doread(m, len) < 0)
8696a9fc400SDavid du Colombier return -1;
8709a747e4fSDavid du Colombier
8719a747e4fSDavid du Colombier /* pullup the header (i.e. everything except data) */
8729a747e4fSDavid du Colombier t = nb->rp[BIT32SZ];
8739a747e4fSDavid du Colombier switch(t){
8749a747e4fSDavid du Colombier case Rread:
8759a747e4fSDavid du Colombier hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
8769a747e4fSDavid du Colombier break;
8779a747e4fSDavid du Colombier default:
8789a747e4fSDavid du Colombier hlen = len;
8799a747e4fSDavid du Colombier break;
8809a747e4fSDavid du Colombier }
8819a747e4fSDavid du Colombier nb = pullupqueue(m->q, hlen);
8829a747e4fSDavid du Colombier
8839a747e4fSDavid du Colombier if(convM2S(nb->rp, len, &r->reply) <= 0){
8849a747e4fSDavid du Colombier /* bad message, dump it */
8859a747e4fSDavid du Colombier print("mntrpcread: convM2S failed\n");
8869a747e4fSDavid du Colombier qdiscard(m->q, len);
8879a747e4fSDavid du Colombier return -1;
8889a747e4fSDavid du Colombier }
8899a747e4fSDavid du Colombier
8909a747e4fSDavid du Colombier /* hang the data off of the fcall struct */
8919a747e4fSDavid du Colombier l = &r->b;
8929a747e4fSDavid du Colombier *l = nil;
8939a747e4fSDavid du Colombier do {
8949a747e4fSDavid du Colombier b = qremove(m->q);
8959a747e4fSDavid du Colombier if(hlen > 0){
8969a747e4fSDavid du Colombier b->rp += hlen;
8979a747e4fSDavid du Colombier len -= hlen;
8989a747e4fSDavid du Colombier hlen = 0;
8999a747e4fSDavid du Colombier }
9009a747e4fSDavid du Colombier i = BLEN(b);
9019a747e4fSDavid du Colombier if(i <= len){
9029a747e4fSDavid du Colombier len -= i;
9039a747e4fSDavid du Colombier *l = b;
9049a747e4fSDavid du Colombier l = &(b->next);
9059a747e4fSDavid du Colombier } else {
9069a747e4fSDavid du Colombier /* split block and put unused bit back */
9079a747e4fSDavid du Colombier nb = allocb(i-len);
9089a747e4fSDavid du Colombier memmove(nb->wp, b->rp+len, i-len);
9099a747e4fSDavid du Colombier b->wp = b->rp+len;
9109a747e4fSDavid du Colombier nb->wp += i-len;
9119a747e4fSDavid du Colombier qputback(m->q, nb);
9129a747e4fSDavid du Colombier *l = b;
9139a747e4fSDavid du Colombier return 0;
9149a747e4fSDavid du Colombier }
9159a747e4fSDavid du Colombier }while(len > 0);
9169a747e4fSDavid du Colombier
9179a747e4fSDavid du Colombier return 0;
9183e12c5d1SDavid du Colombier }
9193e12c5d1SDavid du Colombier
9203e12c5d1SDavid du Colombier void
mntgate(Mnt * m)9213e12c5d1SDavid du Colombier mntgate(Mnt *m)
9223e12c5d1SDavid du Colombier {
9233e12c5d1SDavid du Colombier Mntrpc *q;
9243e12c5d1SDavid du Colombier
9253e12c5d1SDavid du Colombier lock(m);
9263e12c5d1SDavid du Colombier m->rip = 0;
9277dd7cddfSDavid du Colombier for(q = m->queue; q; q = q->list) {
9287dd7cddfSDavid du Colombier if(q->done == 0)
9297dd7cddfSDavid du Colombier if(wakeup(&q->r))
9307dd7cddfSDavid du Colombier break;
9313e12c5d1SDavid du Colombier }
9323e12c5d1SDavid du Colombier unlock(m);
9333e12c5d1SDavid du Colombier }
9343e12c5d1SDavid du Colombier
9353e12c5d1SDavid du Colombier void
mountmux(Mnt * m,Mntrpc * r)9363e12c5d1SDavid du Colombier mountmux(Mnt *m, Mntrpc *r)
9373e12c5d1SDavid du Colombier {
9383e12c5d1SDavid du Colombier Mntrpc **l, *q;
9393e12c5d1SDavid du Colombier
9403e12c5d1SDavid du Colombier lock(m);
9413e12c5d1SDavid du Colombier l = &m->queue;
9423e12c5d1SDavid du Colombier for(q = *l; q; q = q->list) {
9437dd7cddfSDavid du Colombier /* look for a reply to a message */
9447dd7cddfSDavid du Colombier if(q->request.tag == r->reply.tag) {
9453e12c5d1SDavid du Colombier *l = q->list;
9467dd7cddfSDavid du Colombier if(q != r) {
9477dd7cddfSDavid du Colombier /*
9487dd7cddfSDavid du Colombier * Completed someone else.
9497dd7cddfSDavid du Colombier * Trade pointers to receive buffer.
9507dd7cddfSDavid du Colombier */
9517dd7cddfSDavid du Colombier q->reply = r->reply;
9529a747e4fSDavid du Colombier q->b = r->b;
9539a747e4fSDavid du Colombier r->b = nil;
9547dd7cddfSDavid du Colombier }
9553e12c5d1SDavid du Colombier q->done = 1;
9567dd7cddfSDavid du Colombier unlock(m);
9577dd7cddfSDavid du Colombier if(mntstats != nil)
9587dd7cddfSDavid du Colombier (*mntstats)(q->request.type,
9597dd7cddfSDavid du Colombier m->c, q->stime,
9607dd7cddfSDavid du Colombier q->reqlen + r->replen);
9617dd7cddfSDavid du Colombier if(q != r)
9623e12c5d1SDavid du Colombier wakeup(&q->r);
9633e12c5d1SDavid du Colombier return;
9643e12c5d1SDavid du Colombier }
9653e12c5d1SDavid du Colombier l = &q->list;
9663e12c5d1SDavid du Colombier }
9673e12c5d1SDavid du Colombier unlock(m);
9689a747e4fSDavid du Colombier print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
9693e12c5d1SDavid du Colombier }
9703e12c5d1SDavid du Colombier
9717dd7cddfSDavid du Colombier /*
9727dd7cddfSDavid du Colombier * Create a new flush request and chain the previous
9737dd7cddfSDavid du Colombier * requests from it
9747dd7cddfSDavid du Colombier */
9757dd7cddfSDavid du Colombier Mntrpc*
mntflushalloc(Mntrpc * r,ulong iounit)9769a747e4fSDavid du Colombier mntflushalloc(Mntrpc *r, ulong iounit)
9773e12c5d1SDavid du Colombier {
9787dd7cddfSDavid du Colombier Mntrpc *fr;
9793e12c5d1SDavid du Colombier
9809a747e4fSDavid du Colombier fr = mntralloc(0, iounit);
9813e12c5d1SDavid du Colombier
9827dd7cddfSDavid du Colombier fr->request.type = Tflush;
9837dd7cddfSDavid du Colombier if(r->request.type == Tflush)
9847dd7cddfSDavid du Colombier fr->request.oldtag = r->request.oldtag;
9857dd7cddfSDavid du Colombier else
9867dd7cddfSDavid du Colombier fr->request.oldtag = r->request.tag;
9877dd7cddfSDavid du Colombier fr->flushed = r;
9883e12c5d1SDavid du Colombier
9897dd7cddfSDavid du Colombier return fr;
9903e12c5d1SDavid du Colombier }
9917dd7cddfSDavid du Colombier
9927dd7cddfSDavid du Colombier /*
9937dd7cddfSDavid du Colombier * Free a chain of flushes. Remove each unanswered
9947dd7cddfSDavid du Colombier * flush and the original message from the unanswered
9957dd7cddfSDavid du Colombier * request queue. Mark the original message as done
9967dd7cddfSDavid du Colombier * and if it hasn't been answered set the reply to to
9977dd7cddfSDavid du Colombier * Rflush.
9987dd7cddfSDavid du Colombier */
9997dd7cddfSDavid du Colombier void
mntflushfree(Mnt * m,Mntrpc * r)10007dd7cddfSDavid du Colombier mntflushfree(Mnt *m, Mntrpc *r)
10017dd7cddfSDavid du Colombier {
10027dd7cddfSDavid du Colombier Mntrpc *fr;
10037dd7cddfSDavid du Colombier
10047dd7cddfSDavid du Colombier while(r){
10057dd7cddfSDavid du Colombier fr = r->flushed;
10067dd7cddfSDavid du Colombier if(!r->done){
10077dd7cddfSDavid du Colombier r->reply.type = Rflush;
10087dd7cddfSDavid du Colombier mntqrm(m, r);
10097dd7cddfSDavid du Colombier }
10107dd7cddfSDavid du Colombier if(fr)
10117dd7cddfSDavid du Colombier mntfree(r);
10127dd7cddfSDavid du Colombier r = fr;
10137dd7cddfSDavid du Colombier }
10143e12c5d1SDavid du Colombier }
10153e12c5d1SDavid du Colombier
1016d9306527SDavid du Colombier int
alloctag(void)1017d9306527SDavid du Colombier alloctag(void)
1018d9306527SDavid du Colombier {
1019d9306527SDavid du Colombier int i, j;
1020d9306527SDavid du Colombier ulong v;
1021d9306527SDavid du Colombier
1022d9306527SDavid du Colombier for(i = 0; i < NMASK; i++){
1023d9306527SDavid du Colombier v = mntalloc.tagmask[i];
1024d9306527SDavid du Colombier if(v == ~0UL)
1025d9306527SDavid du Colombier continue;
1026d9306527SDavid du Colombier for(j = 0; j < 1<<TAGSHIFT; j++)
1027d9306527SDavid du Colombier if((v & (1<<j)) == 0){
1028d9306527SDavid du Colombier mntalloc.tagmask[i] |= 1<<j;
1029d9306527SDavid du Colombier return (i<<TAGSHIFT) + j;
1030d9306527SDavid du Colombier }
1031d9306527SDavid du Colombier }
1032d9306527SDavid du Colombier panic("no friggin tags left");
1033d9306527SDavid du Colombier return NOTAG;
1034d9306527SDavid du Colombier }
1035d9306527SDavid du Colombier
1036d9306527SDavid du Colombier void
freetag(int t)1037d9306527SDavid du Colombier freetag(int t)
1038d9306527SDavid du Colombier {
1039d9306527SDavid du Colombier mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1040d9306527SDavid du Colombier }
1041d9306527SDavid du Colombier
10423e12c5d1SDavid du Colombier Mntrpc*
mntralloc(Chan * c,ulong msize)10439a747e4fSDavid du Colombier mntralloc(Chan *c, ulong msize)
10443e12c5d1SDavid du Colombier {
10453e12c5d1SDavid du Colombier Mntrpc *new;
10463e12c5d1SDavid du Colombier
10473e12c5d1SDavid du Colombier lock(&mntalloc);
10483e12c5d1SDavid du Colombier new = mntalloc.rpcfree;
10497dd7cddfSDavid du Colombier if(new == nil){
10507dd7cddfSDavid du Colombier new = malloc(sizeof(Mntrpc));
10517dd7cddfSDavid du Colombier if(new == nil) {
10527dd7cddfSDavid du Colombier unlock(&mntalloc);
10537dd7cddfSDavid du Colombier exhausted("mount rpc header");
10547dd7cddfSDavid du Colombier }
10557dd7cddfSDavid du Colombier /*
10567dd7cddfSDavid du Colombier * The header is split from the data buffer as
10577dd7cddfSDavid du Colombier * mountmux may swap the buffer with another header.
10587dd7cddfSDavid du Colombier */
10599a747e4fSDavid du Colombier new->rpc = mallocz(msize, 0);
10607dd7cddfSDavid du Colombier if(new->rpc == nil){
10617dd7cddfSDavid du Colombier free(new);
10623e12c5d1SDavid du Colombier unlock(&mntalloc);
10633e12c5d1SDavid du Colombier exhausted("mount rpc buffer");
10643e12c5d1SDavid du Colombier }
10659a747e4fSDavid du Colombier new->rpclen = msize;
1066d9306527SDavid du Colombier new->request.tag = alloctag();
10673e12c5d1SDavid du Colombier }
10687dd7cddfSDavid du Colombier else {
10697dd7cddfSDavid du Colombier mntalloc.rpcfree = new->list;
10707dd7cddfSDavid du Colombier mntalloc.nrpcfree--;
10719a747e4fSDavid du Colombier if(new->rpclen < msize){
10729a747e4fSDavid du Colombier free(new->rpc);
10739a747e4fSDavid du Colombier new->rpc = mallocz(msize, 0);
10749a747e4fSDavid du Colombier if(new->rpc == nil){
10759a747e4fSDavid du Colombier free(new);
10769a747e4fSDavid du Colombier mntalloc.nrpcused--;
10779a747e4fSDavid du Colombier unlock(&mntalloc);
10789a747e4fSDavid du Colombier exhausted("mount rpc buffer");
10799a747e4fSDavid du Colombier }
10809a747e4fSDavid du Colombier new->rpclen = msize;
10819a747e4fSDavid du Colombier }
10827dd7cddfSDavid du Colombier }
10837dd7cddfSDavid du Colombier mntalloc.nrpcused++;
10843e12c5d1SDavid du Colombier unlock(&mntalloc);
10857dd7cddfSDavid du Colombier new->c = c;
10863e12c5d1SDavid du Colombier new->done = 0;
10877dd7cddfSDavid du Colombier new->flushed = nil;
10889a747e4fSDavid du Colombier new->b = nil;
10893e12c5d1SDavid du Colombier return new;
10903e12c5d1SDavid du Colombier }
10913e12c5d1SDavid du Colombier
10923e12c5d1SDavid du Colombier void
mntfree(Mntrpc * r)10933e12c5d1SDavid du Colombier mntfree(Mntrpc *r)
10943e12c5d1SDavid du Colombier {
10959a747e4fSDavid du Colombier if(r->b != nil)
10969a747e4fSDavid du Colombier freeblist(r->b);
10973e12c5d1SDavid du Colombier lock(&mntalloc);
10987dd7cddfSDavid du Colombier if(mntalloc.nrpcfree >= 10){
10997dd7cddfSDavid du Colombier free(r->rpc);
1100d9306527SDavid du Colombier freetag(r->request.tag);
1101a23bc242SDavid du Colombier free(r);
11027dd7cddfSDavid du Colombier }
11037dd7cddfSDavid du Colombier else{
11043e12c5d1SDavid du Colombier r->list = mntalloc.rpcfree;
11053e12c5d1SDavid du Colombier mntalloc.rpcfree = r;
11067dd7cddfSDavid du Colombier mntalloc.nrpcfree++;
11077dd7cddfSDavid du Colombier }
11087dd7cddfSDavid du Colombier mntalloc.nrpcused--;
11093e12c5d1SDavid du Colombier unlock(&mntalloc);
11103e12c5d1SDavid du Colombier }
11113e12c5d1SDavid du Colombier
11123e12c5d1SDavid du Colombier void
mntqrm(Mnt * m,Mntrpc * r)11133e12c5d1SDavid du Colombier mntqrm(Mnt *m, Mntrpc *r)
11143e12c5d1SDavid du Colombier {
11153e12c5d1SDavid du Colombier Mntrpc **l, *f;
11163e12c5d1SDavid du Colombier
11173e12c5d1SDavid du Colombier lock(m);
11183e12c5d1SDavid du Colombier r->done = 1;
11193e12c5d1SDavid du Colombier
11203e12c5d1SDavid du Colombier l = &m->queue;
11213e12c5d1SDavid du Colombier for(f = *l; f; f = f->list) {
11223e12c5d1SDavid du Colombier if(f == r) {
11233e12c5d1SDavid du Colombier *l = r->list;
11243e12c5d1SDavid du Colombier break;
11253e12c5d1SDavid du Colombier }
11263e12c5d1SDavid du Colombier l = &f->list;
11273e12c5d1SDavid du Colombier }
11283e12c5d1SDavid du Colombier unlock(m);
11293e12c5d1SDavid du Colombier }
11303e12c5d1SDavid du Colombier
11313e12c5d1SDavid du Colombier Mnt*
mntchk(Chan * c)11323e12c5d1SDavid du Colombier mntchk(Chan *c)
11333e12c5d1SDavid du Colombier {
11343e12c5d1SDavid du Colombier Mnt *m;
11353e12c5d1SDavid du Colombier
11369a747e4fSDavid du Colombier /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
11379a747e4fSDavid du Colombier
11389a747e4fSDavid du Colombier if(c->mchan == nil)
11394afe124fSDavid du Colombier panic("mntchk 1: nil mchan c %s\n", chanpath(c));
11409a747e4fSDavid du Colombier
11419a747e4fSDavid du Colombier m = c->mchan->mux;
11429a747e4fSDavid du Colombier
11439a747e4fSDavid du Colombier if(m == nil)
11444afe124fSDavid du Colombier print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
11457dd7cddfSDavid du Colombier
11467dd7cddfSDavid du Colombier /*
11478cd4f5a6SDavid du Colombier * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
11487dd7cddfSDavid du Colombier */
11497dd7cddfSDavid du Colombier if(m->id == 0 || m->id >= c->dev)
11509a747e4fSDavid du Colombier panic("mntchk 3: can't happen");
11517dd7cddfSDavid du Colombier
11523e12c5d1SDavid du Colombier return m;
11533e12c5d1SDavid du Colombier }
11543e12c5d1SDavid du Colombier
11559a747e4fSDavid du Colombier /*
11569a747e4fSDavid du Colombier * Rewrite channel type and dev for in-flight data to
11579a747e4fSDavid du Colombier * reflect local values. These entries are known to be
11589a747e4fSDavid du Colombier * the first two in the Dir encoding after the count.
11599a747e4fSDavid du Colombier */
11603e12c5d1SDavid du Colombier void
mntdirfix(uchar * dirbuf,Chan * c)11613e12c5d1SDavid du Colombier mntdirfix(uchar *dirbuf, Chan *c)
11623e12c5d1SDavid du Colombier {
11639a747e4fSDavid du Colombier uint r;
11647dd7cddfSDavid du Colombier
11657dd7cddfSDavid du Colombier r = devtab[c->type]->dc;
11669a747e4fSDavid du Colombier dirbuf += BIT16SZ; /* skip count */
11679a747e4fSDavid du Colombier PBIT16(dirbuf, r);
11689a747e4fSDavid du Colombier dirbuf += BIT16SZ;
11699a747e4fSDavid du Colombier PBIT32(dirbuf, c->dev);
11703e12c5d1SDavid du Colombier }
11713e12c5d1SDavid du Colombier
11723e12c5d1SDavid du Colombier int
rpcattn(void * v)11737dd7cddfSDavid du Colombier rpcattn(void *v)
11743e12c5d1SDavid du Colombier {
11757dd7cddfSDavid du Colombier Mntrpc *r;
11767dd7cddfSDavid du Colombier
11777dd7cddfSDavid du Colombier r = v;
11783e12c5d1SDavid du Colombier return r->done || r->m->rip == 0;
11793e12c5d1SDavid du Colombier }
11807dd7cddfSDavid du Colombier
11817dd7cddfSDavid du Colombier Dev mntdevtab = {
11827dd7cddfSDavid du Colombier 'M',
11837dd7cddfSDavid du Colombier "mnt",
11847dd7cddfSDavid du Colombier
11857dd7cddfSDavid du Colombier mntreset,
11867dd7cddfSDavid du Colombier devinit,
11879a747e4fSDavid du Colombier devshutdown,
11887dd7cddfSDavid du Colombier mntattach,
11897dd7cddfSDavid du Colombier mntwalk,
11907dd7cddfSDavid du Colombier mntstat,
11917dd7cddfSDavid du Colombier mntopen,
11927dd7cddfSDavid du Colombier mntcreate,
11937dd7cddfSDavid du Colombier mntclose,
11947dd7cddfSDavid du Colombier mntread,
11957dd7cddfSDavid du Colombier devbread,
11967dd7cddfSDavid du Colombier mntwrite,
11977dd7cddfSDavid du Colombier devbwrite,
11987dd7cddfSDavid du Colombier mntremove,
11997dd7cddfSDavid du Colombier mntwstat,
12007dd7cddfSDavid du Colombier };
1201