From fb07b2978cf423f8a9268fcebef7d7def9b6c205 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 4 Jan 2002 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2002-01-04 --- mtx/main.c | 1 + mtx/mmu.c | 23 ++++++-- port/chan.c | 139 +++++++++++++++++++++++++++++++++---------------- port/dev.c | 6 ++- port/devmnt.c | 1 + port/portfns.h | 8 +-- port/sysfile.c | 4 +- 7 files changed, 124 insertions(+), 58 deletions(-) diff --git a/mtx/main.c b/mtx/main.c index a5dfa5238508a94cf0f557c7e29ed28e19c32b98..d9d95d613f1366f68deb2e4310a4d3a47cb78438 100644 --- a/mtx/main.c +++ b/mtx/main.c @@ -137,6 +137,7 @@ init0(void) poperror(); } kproc("alarm", alarmkproc, 0); +print("touser forestalled\n"); for(;;); touser((void*)(USTKTOP-8)); } diff --git a/mtx/mmu.c b/mtx/mmu.c index 9826af3440b970c1e7f13fcd6ad551e51f3eaa64..9fb16e83469172befcd7e228785a5f27821b6277 100644 --- a/mtx/mmu.c +++ b/mtx/mmu.c @@ -5,8 +5,21 @@ #include "fns.h" #include "io.h" -void *ptab; -ulong ptabsize; +/* + * The page table is shared across all processes and processors + * (hence needs to be locked for updates on a multiprocessor). + * Different processes are distinguished via the VSID field in + * the segment registers. As flushing the entire page table is an + * expensive operation, we implement an aging algorithm for + * mmu pids, with a background kproc to purge stale pids en mass. + */ + +static struct { + Lock; + void *base; /* start of page table in kernel virtual space */ + ulong size; /* number of bytes in page table */ + int slotgen; /* used to choose which pte to alocate in pteg */ +} ptab; void mmuinit(void) @@ -22,9 +35,9 @@ mmuinit(void) mem <<= 1; } - ptabsize = (1<<(lhash+6)); - ptab = xspanalloc(ptabsize, 0, ptabsize); - putsdr1(PADDR(ptab) | ((1<<(lhash-10))-1)); + ptab.size = (1<<(lhash+6)); + ptab.base = xspanalloc(ptab.size, 0, ptab.size); + putsdr1(PADDR(ptab.base) | ((1<<(lhash-10))-1)); } void diff --git a/port/chan.c b/port/chan.c index 68567cb07fa9c7abd10c3e97193ccf215c44e382..a49da35b59beb16423e377d3ceac2b5671831ce2 100644 --- a/port/chan.c +++ b/port/chan.c @@ -85,6 +85,7 @@ struct Elemlist char *name; /* copy of name, so '/' can be overwritten */ int nelems; char **elems; + int *off; }; #define SEP(c) ((c) == 0 || (c) == '/') @@ -708,12 +709,14 @@ undomount(Chan *c, Cname *name) } /* - * Either walks all the way or not at all. No partial results. + * Either walks all the way or not at all. No partial results in *cp. + * *nerror is the number of names to display in an error message. */ +static char Edoesnotexist[] = "does not exist"; int -walk(Chan **cp, char **names, int nnames, int nomount) +walk(Chan **cp, char **names, int nnames, int nomount, int *nerror) { - int i, dotdot, n, ntry, type, dev; + int dev, dotdot, i, n, nhave, ntry, type; Chan *c, *nc; Cname *cname; Mount *f; @@ -736,13 +739,21 @@ walk(Chan **cp, char **names, int nnames, int nomount) * An invariant is that each time through the loop, c is on the undomount * side of the mount point, and c's name is cname. */ - while(nnames > 0){ - ntry = nnames; + for(nhave=0; nhaveqid.type&QTDIR)==0){ + if(nerror) + *nerror = nhave; + cnameclose(cname); + cclose(c); + strcpy(up->errstr, Enotdir); + return -1; + } + ntry = nnames - nhave; if(ntry > MAXWELEM) ntry = MAXWELEM; dotdot = 0; - for(i=0; itype; dev = c->dev; - if((wq = devtab[type]->walk(c, nil, names, ntry)) == nil){ + if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){ /* try a union mount, if any */ - if(mh == nil || nomount){ - Giveup: + if(mh && !nomount){ + /* + * mh->mount == c, so start at mh->mount->next + */ + rlock(&mh->lock); + for(f = mh->mount->next; f; f = f->next) + if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil) + break; + runlock(&mh->lock); + if(f != nil){ + type = f->to->type; + dev = f->to->dev; + } + } + if(wq == nil){ cclose(c); cnameclose(cname); + if(nerror) + *nerror = nhave+1; return -1; } - - rlock(&mh->lock); - if(waserror()){ - runlock(&mh->lock); - nexterror(); - } - /* - * mh->mount == c, so start at mh->mount->next - */ - for(f = mh->mount->next; f; f = f->next) - if((wq = devtab[f->to->type]->walk(f->to, nil, names, ntry)) != nil) - break; - poperror(); - runlock(&mh->lock); - - if(wq == nil) - goto Giveup; - - type = f->to->type; - dev = f->to->dev; } nmh = nil; @@ -806,6 +812,15 @@ walk(Chan **cp, char **names, int nnames, int nomount) if(wq->clone == nil){ cclose(c); cnameclose(cname); + if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){ + if(nerror) + *nerror = nhave+wq->nqid+1; + strcpy(up->errstr, Edoesnotexist); + }else{ + if(nerror) + *nerror = nhave+wq->nqid; + strcpy(up->errstr, Enotdir); + } free(wq); return -1; } @@ -819,15 +834,12 @@ walk(Chan **cp, char **names, int nnames, int nomount) n = i+1; } for(i=0; inelems % Delta == 0){ @@ -917,6 +932,10 @@ growparse(Elemlist *e) memmove(new, e->elems, e->nelems*sizeof(char*)); free(e->elems); e->elems = new; + inew = smalloc((e->nelems+Delta+1) * sizeof(int)); + memmove(inew, e->off, e->nelems*sizeof(int)); + free(e->off); + e->off = inew; } } @@ -934,20 +953,38 @@ parsename(char *name, Elemlist *e) name = e->name; e->nelems = 0; e->elems = nil; + e->off = smalloc(sizeof(int)); + e->off[0] = 0; for(;;){ name = skipslash(name); if(*name=='\0') break; growparse(e); + e->elems[e->nelems++] = name; slash = utfrune(name, '/'); - if(slash == nil) + if(slash == nil){ + e->off[e->nelems] = name+strlen(name) - e->name; break; + } + e->off[e->nelems] = slash - e->name; *slash++ = '\0'; name = slash; } } +void* +memrchr(void *va, int c, long n) +{ + uchar *a, *e; + + a = va; + for(e=a+n-1; e>a; e--) + if(*e == c) + return e; + return nil; +} + /* * Turn a name into a channel. * &name[0] is known to be a valid address. It may be a kernel address. @@ -967,7 +1004,7 @@ parsename(char *name, Elemlist *e) Chan* namec(char *aname, int amode, int omode, ulong perm) { - int n, t, nomount; + int n, prefix, len, t, nomount, npath; Chan *c, *cnew; Cname *cname; Elemlist e; @@ -1034,19 +1071,17 @@ namec(char *aname, int amode, int omode, ulong perm) name = skipslash(name); break; } + prefix = name - aname; e.name = nil; e.elems = nil; + e.off = nil; + e.nelems = 0; if(waserror()){ - if(strcmp(up->errstr, Enonexist) == 0){ - if(strlen(aname) < ERRMAX/3 || (name=strrchr(aname, '/'))==nil || name==aname) - snprint(up->errstr, ERRMAX, "\"%s\" does not exist", aname); - else - snprint(up->errstr, ERRMAX, "file \"...%s\" does not exist", name); - } cclose(c); free(e.name); free(e.elems); + free(e.off); //dumpmount(); nexterror(); } @@ -1065,8 +1100,19 @@ namec(char *aname, int amode, int omode, ulong perm) e.nelems--; } - if(walk(&c, e.elems, e.nelems, nomount) < 0) - error(Enonexist); + if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){ + if(npath < 0 || npath > e.nelems){ + print("namec %s walk error npath=%d\n", aname, npath); + nexterror(); + } + len = prefix+e.off[npath]; + strcpy(tmperrbuf, up->errstr); + if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname) + snprint(up->errstr, ERRMAX, "\"%.*s\" %s", len, aname, tmperrbuf); + else + snprint(up->errstr, ERRMAX, "\"...%.*s\" %s", (int)(len-(name-aname)), name, tmperrbuf); + nexterror(); + } switch(amode){ case Aaccess: @@ -1156,7 +1202,7 @@ if(c->umh != nil){ * If omode&OEXCL is set, just give up. */ e.nelems++; - if(walk(&c, e.elems+e.nelems-1, 1, nomount) == 0){ + if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){ if(omode&OEXCL) error(Eexist); omode |= OTRUNC; @@ -1246,7 +1292,7 @@ if(c->umh != nil){ createerr = up->errstr; up->errstr = tmperrbuf; /* note: we depend that walk does not error */ - if(walk(&c, e.elems+e.nelems-1, 1, nomount) < 0){ + if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){ up->errstr = createerr; error(createerr); /* report true error */ } @@ -1269,6 +1315,7 @@ if(c->umh != nil){ kstrcpy(up->genbuf, ".", sizeof up->genbuf); free(e.name); free(e.elems); + free(e.off); return c; } diff --git a/port/dev.c b/port/dev.c index 236aab66bd7e1a6c4e569c5be4b448188be6a457..bc5ed0f162febb63cea4584c45b52d5fe96ffb0c 100644 --- a/port/dev.c +++ b/port/dev.c @@ -147,7 +147,11 @@ devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen wq->clone = nc; for(j=0; jqid.type&QTDIR)){ + if(j==0) + error(Enotdir); + goto Done; + } n = name[j]; if(strcmp(n, ".") == 0){ Accept: diff --git a/port/devmnt.c b/port/devmnt.c index bc59b351a5e60060ab5f044322fc0e7d9ce3975d..ade2edce84ef27bbe86c15f1f0898fa3c5a46c44 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -450,6 +450,7 @@ mntwalk(Chan *c, Chan *nc, char **name, int nname) wq->qid[i] = r->reply.wqid[i]; Return: + poperror(); mntfree(r); poperror(); diff --git a/port/portfns.h b/port/portfns.h index 5c380a8d1c8c874b5c1f8e82bb57dc9d11796417..21017790d17b8f48acee763e078001f0ddc28303 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -16,7 +16,7 @@ int blocklen(Block*); void cachedel(Image*, ulong); void cachepage(Page*, Image*); void callwithureg(void(*)(Ureg*)); -char* c2name(Chan*); +char* c2name(Chan*); int cangetc(void*); int canlock(Lock*); int canpage(Proc*); @@ -60,7 +60,7 @@ void delay(int); Chan* devattach(int, char*); Block* devbread(Chan*, long, ulong); long devbwrite(Chan*, Block*, ulong); -Chan* devclone(Chan*); +Chan* devclone(Chan*); int devconfig(int, char *, DevConf *); void devcreate(Chan*, char*, int, ulong); void devdir(Chan*, Qid, char*, vlong, char*, long, Dir*); @@ -74,7 +74,7 @@ void devpower(int); void devremove(Chan*); void devreset(void); int devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*); -Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*); +Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*); int devwstat(Chan*, uchar*, int); void drawactive(int); void drawcmap(void); @@ -336,7 +336,7 @@ void validstat(uchar*, int); void vcacheinval(Page*, ulong); void* vmemchr(void*, int, int); Proc* wakeup(Rendez*); -int walk(Chan**, char**, int, int); +int walk(Chan**, char**, int, int, int*); void wlock(RWlock*); void wunlock(RWlock*); void* xalloc(ulong); diff --git a/port/sysfile.c b/port/sysfile.c index 83ba36219ff5618df84cb27a706d232af2056205..c9d053a2cada12a828b6d8b1df4e621aa95e496e 100644 --- a/port/sysfile.c +++ b/port/sysfile.c @@ -197,9 +197,9 @@ syspipe(ulong *arg) nexterror(); } c[1] = cclone(c[0]); - if(walk(&c[0], datastr+0, 1, 1) < 0) + if(walk(&c[0], datastr+0, 1, 1, nil) < 0) error(Egreg); - if(walk(&c[1], datastr+1, 1, 1) < 0) + if(walk(&c[1], datastr+1, 1, 1, nil) < 0) error(Egreg); c[0] = d->open(c[0], ORDWR); c[1] = d->open(c[1], ORDWR);