plan 9 kernel history: overview | file list | diff list |
1990/0227/port/devmnt.c (diff list | history)
port/devmnt.c on 1990/0227 | ||
1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "errno.h" #include "devtab.h" #include "fcall.h" /* * Easy version: multiple sessions but no intra-session multiplexing, copy the data */ typedef struct Mnt Mnt; struct Mnt { Ref; /* for number of chans, incl. mntpt but not msg */ QLock; /* for access */ Chan *msg; /* for reading and writing messages */ Chan *mntpt; /* channel in user's name space */ }; #define BUFSIZE (MAXFDATA+500) /* BUG */ typedef struct Mntbuf Mntbuf; struct Mntbuf { Mntbuf *next; char buf[BUFSIZE]; }; struct { Lock; Mntbuf *free; }mntbufalloc; typedef struct Mnthdr Mnthdr; struct Mnthdr /* next only meaningful when buffer isn't being used */ { Mnthdr *next; Fcall thdr; Fcall rhdr; }; struct { Lock; Mnthdr *free; }mnthdralloc; Mnt *mnt; void mntxmit(Mnt*, Mnthdr*); Mntbuf* mballoc(void) { Mntbuf *mb; loop: lock(&mntbufalloc); if(mb = mntbufalloc.free){ /* assign = */ mntbufalloc.free = mb->next; unlock(&mntbufalloc); return mb; } unlock(&mntbufalloc); print("no mntbufs\n"); if(u == 0) panic("mballoc"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); goto loop; } void mbfree(Mntbuf *mb) { lock(&mntbufalloc); mb->next = mntbufalloc.free; mntbufalloc.free = mb; unlock(&mntbufalloc); } Mnthdr* mhalloc(void) { Mnthdr *mh; loop: lock(&mnthdralloc); if(mh = mnthdralloc.free){ /* assign = */ mnthdralloc.free = mh->next; unlock(&mnthdralloc); return mh; } unlock(&mnthdralloc); print("no mnthdrs\n"); if(u == 0) panic("mballoc"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); goto loop; } void mhfree(Mnthdr *mh) { lock(&mnthdralloc); mh->next = mnthdralloc.free; mnthdralloc.free = mh; unlock(&mnthdralloc); } Mnt* mntdev(int dev, int noerr) { Mnt *m; if(dev<0 || conf.nmntdev<=dev){ if(noerr) return 0; panic("mntdev out of range"); } m = &mnt[dev]; if(m->msg == 0){ if(noerr) return 0; error(0, Eshutdown); } return m; } void mntreset(void) { int i; Mntbuf *mb; Mnthdr *mh; mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0); mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0); for(i=0; i<conf.nmntbuf-1; i++) mb[i].next = &mb[i+1]; mb[i].next = 0; mntbufalloc.free = mb; mh = ialloc(conf.nmnthdr*sizeof(Mnthdr), 0); for(i=0; i<conf.nmnthdr-1; i++) mh[i].next = &mh[i+1]; mh[i].next = 0; mnthdralloc.free = mh; } void mntinit(void) { } Chan* mntattach(char *spec) { int i; Mnt *m; Mnthdr *mh; Chan *c, *cm; struct bogus{ Chan *chan; char *spec; }bogus; bogus = *((struct bogus *)spec); spec = bogus.spec; m = mnt; for(i=0; i<conf.nmntdev; i++,m++){ lock(m); if(m->ref == 0) goto Found; unlock(m); } error(0, Enomntdev); Found: m->ref = 1; unlock(m); c = devattach('M', spec); c->dev = m - mnt; m->mntpt = c; cm = bogus.chan; m->msg = cm; incref(cm); mh = mhalloc(); if(waserror()){ mhfree(mh); close(c); nexterror(); } mh->thdr.type = Tattach; mh->thdr.fid = c->fid; memcpy(mh->thdr.uname, u->p->pgrp->user, NAMELEN); strcpy(mh->thdr.aname, spec); mntxmit(m, mh); c->qid = mh->rhdr.qid; mhfree(mh); poperror(); return c; } Chan* mntclone(Chan *c, Chan *nc) { Mnt *m; Mnthdr *mh; int new; new = 0; if(nc == 0){ nc = newchan(); new = 1; if(waserror()){ close(nc); nexterror(); } } m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Tclone; mh->thdr.fid = c->fid; mh->thdr.newfid = nc->fid; mntxmit(m, mh); nc->type = c->type; nc->dev = c->dev; nc->qid = c->qid; nc->mode = c->mode; nc->flag = c->flag; nc->offset = c->offset; nc->mnt = c->mnt; if(new) poperror(); mhfree(mh); poperror(); incref(m); return nc; } int mntwalk(Chan *c, char *name) { Mnt *m; Mnthdr *mh; int found; found = 1; m = mntdev(c->dev, 0); mh = mhalloc(); mh->thdr.type = Twalk; mh->thdr.fid = c->fid; strcpy(mh->thdr.name, name); if(waserror()){ /* BUG: can check type of error? */ found = 0; goto Out; } mntxmit(m, mh); c->qid = mh->rhdr.qid; poperror(); Out: mhfree(mh); return found; } void mntstat(Chan *c, char *dp) { Mnt *m; Mnthdr *mh; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Tstat; mh->thdr.fid = c->fid; mntxmit(m, mh); memcpy(dp, mh->rhdr.stat, DIRLEN); dp[DIRLEN-4] = devchar[c->type]; dp[DIRLEN-3] = 0; dp[DIRLEN-2] = c->dev; dp[DIRLEN-1] = c->dev>>8; mhfree(mh); poperror(); } Chan* mntopen(Chan *c, int omode) { Mnt *m; Mnthdr *mh; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Topen; mh->thdr.fid = c->fid; mh->thdr.mode = omode; mntxmit(m, mh); c->qid = mh->rhdr.qid; mhfree(mh); poperror(); c->offset = 0; c->mode = openmode(omode); c->flag |= COPEN; return c; } void mntcreate(Chan *c, char *name, int omode, ulong perm) { Mnt *m; Mnthdr *mh; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Tcreate; mh->thdr.fid = c->fid; strcpy(mh->thdr.name, name); mh->thdr.mode = omode; mh->thdr.perm = perm; mntxmit(m, mh); c->qid = mh->rhdr.qid; mhfree(mh); poperror(); c->flag |= COPEN; c->mode = openmode(omode); c->qid = mh->rhdr.qid; } void mntclose(Chan *c) { Mnt *m; Mnthdr *mh; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Tclunk; mh->thdr.fid = c->fid; mntxmit(m, mh); mhfree(mh); if(c == m->mntpt) m->mntpt = 0; if(decref(m) == 0){ /* BUG: need to hang up all pending i/o */ qlock(m); close(m->msg); m->msg = 0; qunlock(m); } poperror(); } long mntreadwrite(Chan *c, void *vbuf, long n, int type) { Mnt *m; Mnthdr *mh; long nt, nr, count, offset; char *buf; buf = vbuf; count = 0; offset = c->offset; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = type; mh->thdr.fid = c->fid; Loop: nt = n; if(nt > MAXFDATA) nt = MAXFDATA; mh->thdr.offset = offset; mh->thdr.count = nt; mh->thdr.data = buf; mntxmit(m, mh); nr = mh->rhdr.count; offset += nr; count += nr; buf += nr; n -= nr; if(n && nr==nt) goto Loop; mhfree(mh); poperror(); return count; } long mntread(Chan *c, void *buf, long n) { long i; uchar *b; n = mntreadwrite(c, buf, n, Tread); if(c->qid & CHDIR){ b = (uchar*)buf; for(i=n-DIRLEN; i>=0; i-=DIRLEN){ b[DIRLEN-4] = devchar[c->type]; b[DIRLEN-3] = 0; b[DIRLEN-2] = c->dev; b[DIRLEN-1] = c->dev>>8; b += DIRLEN; } } return n; } long mntwrite(Chan *c, void *buf, long n) { return mntreadwrite(c, buf, n, Twrite); } void mntremove(Chan *c) { Mnt *m; Mnthdr *mh; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Tremove; mh->thdr.fid = c->fid; mntxmit(m, mh); mhfree(mh); poperror(); } void mntwstat(Chan *c, char *dp) { Mnt *m; Mnthdr *mh; m = mntdev(c->dev, 0); mh = mhalloc(); if(waserror()){ mhfree(mh); nexterror(); } mh->thdr.type = Twstat; mh->thdr.fid = c->fid; memcpy(mh->thdr.stat, dp, DIRLEN); mntxmit(m, mh); mhfree(mh); poperror(); } void mnterrstr(Error *e, char *buf) { Mnt *m; Mnthdr *mh; char *def="mounted device shut down"; m = mntdev(e->dev, 1); if(m == 0){ strcpy(buf, def); return; } mh = mhalloc(); if(waserror()){ strcpy(buf, def); mhfree(mh); nexterror(); } mh->thdr.type = Terrstr; mh->thdr.fid = 0; mh->thdr.err = e->code; mntxmit(m, mh); strcpy(buf, (char*)mh->rhdr.ename); mhfree(mh); poperror(); } void mntuserstr(Error *e, char *buf) { Mnt *m; Mnthdr *mh; char *def="mounted device shut down"; m = mntdev(e->dev, 1); if(m == 0){ strcpy(buf, def); return; } mh = mhalloc(); if(waserror()){ strcpy(buf, def); mhfree(mh); nexterror(); } mh->thdr.type = Tuserstr; mh->thdr.fid = 0; mh->thdr.uid = e->code; mntxmit(m, mh); strcpy(buf, (char*)mh->rhdr.uname); mhfree(mh); poperror(); } void mntxmit(Mnt *m, Mnthdr *mh) { ulong n; Mntbuf *mbr, *mbw; Chan *mntpt; mbr = mballoc(); mbw = mballoc(); if(waserror()){ mbfree(mbr); mbfree(mbw); nexterror(); } n = convS2M(&mh->thdr, mbw->buf); qlock(m); if(m->msg == 0){ qunlock(m); error(0, Eshutdown); } qlock(m->msg); if(waserror()){ qunlock(m); qunlock(m->msg); nexterror(); } if((*devtab[m->msg->type].write)(m->msg, mbw->buf, n) != n){ pprint("short write in mntxmit\n"); error(0, Egreg); } /* * Read response */ n = (*devtab[m->msg->type].read)(m->msg, mbr->buf, BUFSIZE); qunlock(m); qunlock(m->msg); poperror(); if(convM2S(mbr->buf, &mh->rhdr, n) == 0){ pprint("format error in mntxmit\n"); error(0, Egreg); } /* * Various checks */ if(mh->rhdr.type != mh->thdr.type+1){ pprint("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1); error(0, Egreg); } if(mh->rhdr.fid != mh->thdr.fid){ pprint("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type); error(0, Egreg); } if(mh->rhdr.err){ mntpt = m->mntpt; /* unsafe, but Errors are unsafe anyway */ if(mntpt) error(mntpt, mh->rhdr.err); error(0, Eshutdown); } /* * Copy out on read */ if(mh->thdr.type == Tread) memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); mbfree(mbr); mbfree(mbw); poperror(); } |