devsegment: cleanups

- return distinct error message when attempting to create Globalseg with physseg name
- copy directory name to up->genbuf so it stays valid after we unlock(&glogalseglock)
- cleanup wstat() handling, allow changing uid
- make sure global segment size is below SEGMAXSIZE
- move isoverlap() check from globalsegattach() into segattach()
- remove Proc* argument from globalsegattach(), segattach() and isoverlap()
- make Physseg.attr and segattach attr parameter an int for consistency
This commit is contained in:
cinap_lenrek 2016-03-30 22:49:13 +02:00
parent f846721035
commit 1057a859b8
5 changed files with 62 additions and 61 deletions

View file

@ -34,8 +34,8 @@ static Globalseg *globalseg[100];
static Lock globalseglock; static Lock globalseglock;
Segment* (*_globalsegattach)(Proc*, char*); Segment* (*_globalsegattach)(char*);
static Segment* globalsegattach(Proc *p, char *name); static Segment* globalsegattach(char *name);
static Segment* fixedseg(uintptr va, ulong len); static Segment* fixedseg(uintptr va, ulong len);
@ -64,7 +64,7 @@ getgseg(Chan *c)
static void static void
putgseg(Globalseg *g) putgseg(Globalseg *g)
{ {
if(decref(g) > 0) if(g == nil || decref(g))
return; return;
if(g->s != nil) if(g->s != nil)
putseg(g->s); putseg(g->s);
@ -103,9 +103,9 @@ segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
q.vers = 0; q.vers = 0;
q.path = PATH(s, Qsegdir); q.path = PATH(s, Qsegdir);
q.type = QTDIR; q.type = QTDIR;
devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp); kstrcpy(up->genbuf, g->name, sizeof up->genbuf);
devdir(c, q, up->genbuf, 0, g->uid, DMDIR|0777, dp);
unlock(&globalseglock); unlock(&globalseglock);
break; break;
case Qsegdir: case Qsegdir:
if(s == DEVDOTDOT){ if(s == DEVDOTDOT){
@ -183,16 +183,6 @@ segmentopen(Chan *c, int omode)
error(Eisdir); error(Eisdir);
break; break;
case Qctl: case Qctl:
g = getgseg(c);
if(waserror()){
putgseg(g);
nexterror();
}
devpermcheck(g->uid, g->perm, omode);
c->aux = g;
poperror();
c->flag |= COPEN;
break;
case Qdata: case Qdata:
g = getgseg(c); g = getgseg(c);
if(waserror()){ if(waserror()){
@ -200,27 +190,31 @@ segmentopen(Chan *c, int omode)
nexterror(); nexterror();
} }
devpermcheck(g->uid, g->perm, omode); devpermcheck(g->uid, g->perm, omode);
if(g->s == nil) if(TYPE(c) == Qdata && g->s == nil)
error("segment not yet allocated"); error("segment not yet allocated");
c->aux = g; c->aux = g;
poperror(); poperror();
c->flag |= COPEN;
break; break;
default: default:
panic("segmentopen"); panic("segmentopen");
} }
c->mode = openmode(omode); c->mode = openmode(omode);
c->offset = 0; c->offset = 0;
c->flag |= COPEN;
return c; return c;
} }
static void static void
segmentclose(Chan *c) segmentclose(Chan *c)
{ {
if(TYPE(c) == Qtopdir) switch(TYPE(c)){
return; case Qctl:
if(c->flag & COPEN) case Qdata:
putgseg(c->aux); if(c->flag & COPEN){
putgseg(c->aux);
c->aux = nil;
}
}
} }
static Chan* static Chan*
@ -232,8 +226,11 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
if(TYPE(c) != Qtopdir) if(TYPE(c) != Qtopdir)
error(Eperm); error(Eperm);
if(strlen(name) >= sizeof(up->genbuf))
error(Etoolong);
if(findphysseg(name) != nil) if(findphysseg(name) != nil)
error(Eexist); error("name collision with physical segment");
if((perm & DMDIR) == 0) if((perm & DMDIR) == 0)
error(Ebadarg); error(Ebadarg);
@ -249,10 +246,8 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
if(g == nil){ if(g == nil){
if(xfree < 0) if(xfree < 0)
xfree = x; xfree = x;
} else { } else if(strcmp(g->name, name) == 0)
if(strcmp(g->name, name) == 0) error(Eexist);
error(Eexist);
}
} }
if(xfree < 0) if(xfree < 0)
error("too many global segments"); error("too many global segments");
@ -269,7 +264,6 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
c->qid.type = QTDIR; c->qid.type = QTDIR;
c->qid.vers = 0; c->qid.vers = 0;
c->mode = openmode(omode); c->mode = openmode(omode);
c->mode = OWRITE;
return c; return c;
} }
@ -330,13 +324,15 @@ segmentwrite(Chan *c, void *a, long n, vlong voff)
va = va&~(BY2PG-1); va = va&~(BY2PG-1);
if(va == 0 || top > USTKTOP || top <= va) if(va == 0 || top > USTKTOP || top <= va)
error(Ebadarg); error(Ebadarg);
len = (top - va) / BY2PG; len = top - va;
if(len > SEGMAXSIZE)
error(Enovmem);
if(cb->nf >= 4 && strcmp(cb->f[3], "fixed") == 0){ if(cb->nf >= 4 && strcmp(cb->f[3], "fixed") == 0){
if(!iseve()) if(!iseve())
error(Eperm); error(Eperm);
g->s = fixedseg(va, len); g->s = fixedseg(va, len/BY2PG);
} else } else
g->s = newseg(SG_SHARED, va, len); g->s = newseg(SG_SHARED, va, len/BY2PG);
} else } else
error(Ebadctl); error(Ebadctl);
free(cb); free(cb);
@ -359,22 +355,27 @@ segmentwstat(Chan *c, uchar *dp, int n)
if(c->qid.type == QTDIR) if(c->qid.type == QTDIR)
error(Eperm); error(Eperm);
d = nil;
g = getgseg(c); g = getgseg(c);
if(waserror()){ if(waserror()){
free(d);
putgseg(g); putgseg(g);
nexterror(); nexterror();
} }
if(strcmp(g->uid, up->user) && !iseve()) if(strcmp(g->uid, up->user) && !iseve())
error(Eperm); error(Eperm);
d = smalloc(sizeof(Dir)+n); d = smalloc(sizeof(Dir)+n);
n = convM2D(dp, n, &d[0], (char*)&d[1]); n = convM2D(dp, n, &d[0], (char*)&d[1]);
g->perm = d->mode & 0777; if(n == 0)
error(Eshortstat);
if(!emptystr(d->uid))
kstrdup(&g->uid, d->uid);
if(d->mode != ~0UL)
g->perm = d->mode&0777;
free(d);
putgseg(g); putgseg(g);
poperror(); poperror();
free(d);
return n; return n;
} }
@ -399,13 +400,12 @@ segmentremove(Chan *c)
* called by segattach() * called by segattach()
*/ */
static Segment* static Segment*
globalsegattach(Proc *p, char *name) globalsegattach(char *name)
{ {
int x; int x;
Globalseg *g; Globalseg *g;
Segment *s; Segment *s;
g = nil;
if(waserror()){ if(waserror()){
unlock(&globalseglock); unlock(&globalseglock);
nexterror(); nexterror();
@ -414,19 +414,16 @@ globalsegattach(Proc *p, char *name)
for(x = 0; x < nelem(globalseg); x++){ for(x = 0; x < nelem(globalseg); x++){
g = globalseg[x]; g = globalseg[x];
if(g != nil && strcmp(g->name, name) == 0) if(g != nil && strcmp(g->name, name) == 0)
break; goto Found;
}
if(x == nelem(globalseg)){
unlock(&globalseglock);
poperror();
return nil;
} }
unlock(&globalseglock);
poperror();
return nil;
Found:
devpermcheck(g->uid, g->perm, ORDWR); devpermcheck(g->uid, g->perm, ORDWR);
s = g->s; s = g->s;
if(s == nil) if(s == nil)
error("global segment not assigned a virtual address"); error("global segment not assigned a virtual address");
if(isoverlap(p, s->base, s->top - s->base) != nil)
error("overlaps existing segment");
incref(s); incref(s);
unlock(&globalseglock); unlock(&globalseglock);
poperror(); poperror();

View file

@ -389,7 +389,7 @@ enum
struct Physseg struct Physseg
{ {
ulong attr; /* Segment attributes */ int attr; /* Segment attributes */
char *name; /* Attach name */ char *name; /* Attach name */
uintptr pa; /* Physical address */ uintptr pa; /* Physical address */
uintptr size; /* Maximum segment size in bytes */ uintptr size; /* Maximum segment size in bytes */

View file

@ -140,7 +140,7 @@ int iprint(char*, ...);
void isdir(Chan*); void isdir(Chan*);
int iseve(void); int iseve(void);
int islo(void); int islo(void);
Segment* isoverlap(Proc*, uintptr, uintptr); Segment* isoverlap(uintptr, uintptr);
Physseg* findphysseg(char*); Physseg* findphysseg(char*);
void ixsummary(void); void ixsummary(void);
void kickpager(void); void kickpager(void);
@ -309,7 +309,7 @@ void scheddump(void);
void schedinit(void); void schedinit(void);
void (*screenputs)(char*, int); void (*screenputs)(char*, int);
long seconds(void); long seconds(void);
uintptr segattach(Proc*, ulong, char *, uintptr, uintptr); uintptr segattach(int, char *, uintptr, uintptr);
void segclock(uintptr); void segclock(uintptr);
long segio(Segio*, Segment*, void*, long, vlong, int); long segio(Segio*, Segment*, void*, long, vlong, int);
void segpage(Segment*, Page*); void segpage(Segment*, Page*);

View file

@ -27,7 +27,7 @@ static struct Imagealloc
QLock ireclaim; /* mutex on reclaiming free images */ QLock ireclaim; /* mutex on reclaiming free images */
}imagealloc; }imagealloc;
Segment* (*_globalsegattach)(Proc*, char*); Segment* (*_globalsegattach)(char*);
void void
initseg(void) initseg(void)
@ -533,7 +533,7 @@ mfreeseg(Segment *s, uintptr start, ulong pages)
} }
Segment* Segment*
isoverlap(Proc *p, uintptr va, uintptr len) isoverlap(uintptr va, uintptr len)
{ {
int i; int i;
Segment *ns; Segment *ns;
@ -541,7 +541,7 @@ isoverlap(Proc *p, uintptr va, uintptr len)
newtop = va+len; newtop = va+len;
for(i = 0; i < NSEG; i++) { for(i = 0; i < NSEG; i++) {
ns = p->seg[i]; ns = up->seg[i];
if(ns == nil) if(ns == nil)
continue; continue;
if((newtop > ns->base && newtop <= ns->top) || if((newtop > ns->base && newtop <= ns->top) ||
@ -590,7 +590,7 @@ findphysseg(char *name)
} }
uintptr uintptr
segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len) segattach(int attr, char *name, uintptr va, uintptr len)
{ {
int sno; int sno;
Segment *s, *os; Segment *s, *os;
@ -600,7 +600,7 @@ segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
error(Ebadarg); error(Ebadarg);
for(sno = 0; sno < NSEG; sno++) for(sno = 0; sno < NSEG; sno++)
if(p->seg[sno] == nil && sno != ESEG) if(up->seg[sno] == nil && sno != ESEG)
break; break;
if(sno == NSEG) if(sno == NSEG)
@ -611,9 +611,13 @@ segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
* same name * same name
*/ */
if(_globalsegattach != nil){ if(_globalsegattach != nil){
s = (*_globalsegattach)(p, name); s = (*_globalsegattach)(name);
if(s != nil){ if(s != nil){
p->seg[sno] = s; if(isoverlap(s->base, s->top - s->base) != nil){
putseg(s);
error(Esoverlap);
}
up->seg[sno] = s;
return s->base; return s->base;
} }
} }
@ -634,7 +638,7 @@ segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
* map the zero page. * map the zero page.
*/ */
if(va == 0) { if(va == 0) {
for (os = p->seg[SSEG]; os != nil; os = isoverlap(p, va, len)) { for (os = up->seg[SSEG]; os != nil; os = isoverlap(va, len)) {
va = os->base; va = os->base;
if(len >= va) if(len >= va)
error(Enovmem); error(Enovmem);
@ -646,7 +650,7 @@ segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
if(va == 0 || (va+len) > USTKTOP || (va+len) < va) if(va == 0 || (va+len) > USTKTOP || (va+len) < va)
error(Ebadarg); error(Ebadarg);
if(isoverlap(p, va, len) != nil) if(isoverlap(va, len) != nil)
error(Esoverlap); error(Esoverlap);
ps = findphysseg(name); ps = findphysseg(name);
@ -661,7 +665,7 @@ segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
s = newseg(attr, va, len/BY2PG); s = newseg(attr, va, len/BY2PG);
s->pseg = ps; s->pseg = ps;
p->seg[sno] = s; up->seg[sno] = s;
return va; return va;
} }

View file

@ -429,7 +429,7 @@ sysexec(va_list list)
tstk = s->base; tstk = s->base;
if(tstk <= USTKSIZE) if(tstk <= USTKSIZE)
error(Enovmem); error(Enovmem);
} while((s = isoverlap(up, tstk-USTKSIZE, USTKSIZE)) != nil); } while((s = isoverlap(tstk-USTKSIZE, USTKSIZE)) != nil);
up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG); up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG);
/* /*
@ -785,12 +785,12 @@ syssegbrk(va_list list)
uintptr uintptr
syssegattach(va_list list) syssegattach(va_list list)
{ {
ulong attr; int attr;
char *name; char *name;
uintptr va; uintptr va;
ulong len; ulong len;
attr = va_arg(list, ulong); attr = va_arg(list, int);
name = va_arg(list, char*); name = va_arg(list, char*);
va = va_arg(list, uintptr); va = va_arg(list, uintptr);
len = va_arg(list, ulong); len = va_arg(list, ulong);
@ -800,7 +800,7 @@ syssegattach(va_list list)
free(name); free(name);
nexterror(); nexterror();
} }
va = segattach(up, attr, name, va, len); va = segattach(attr, name, va, len);
free(name); free(name);
poperror(); poperror();
return va; return va;