ref: 1057a859b8aa0270f330b2fc11118e1f5f924d74
parent: f8467210359d5c4e576e8c4aa89177902517ec5b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Mar 30 18:49:13 EDT 2016
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
--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -34,8 +34,8 @@
static Lock globalseglock;
- Segment* (*_globalsegattach)(Proc*, char*);
-static Segment* globalsegattach(Proc *p, char *name);
+ Segment* (*_globalsegattach)(char*);
+static Segment* globalsegattach(char *name);
static Segment* fixedseg(uintptr va, ulong len);
@@ -64,7 +64,7 @@
static void
putgseg(Globalseg *g)
{
- if(decref(g) > 0)
+ if(g == nil || decref(g))
return;
if(g->s != nil)
putseg(g->s);
@@ -103,9 +103,9 @@
q.vers = 0;
q.path = PATH(s, Qsegdir);
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);
-
break;
case Qsegdir:
if(s == DEVDOTDOT){
@@ -183,16 +183,6 @@
error(Eisdir);
break;
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:
g = getgseg(c);
if(waserror()){
@@ -200,11 +190,10 @@
nexterror();
}
devpermcheck(g->uid, g->perm, omode);
- if(g->s == nil)
+ if(TYPE(c) == Qdata && g->s == nil)
error("segment not yet allocated");
c->aux = g;
poperror();
- c->flag |= COPEN;
break;
default:
panic("segmentopen");
@@ -211,6 +200,7 @@
}
c->mode = openmode(omode);
c->offset = 0;
+ c->flag |= COPEN;
return c;
}
@@ -217,10 +207,14 @@
static void
segmentclose(Chan *c)
{
- if(TYPE(c) == Qtopdir)
- return;
- if(c->flag & COPEN)
- putgseg(c->aux);
+ switch(TYPE(c)){
+ case Qctl:
+ case Qdata:
+ if(c->flag & COPEN){
+ putgseg(c->aux);
+ c->aux = nil;
+ }
+ }
}
static Chan*
@@ -232,8 +226,11 @@
if(TYPE(c) != Qtopdir)
error(Eperm);
+ if(strlen(name) >= sizeof(up->genbuf))
+ error(Etoolong);
+
if(findphysseg(name) != nil)
- error(Eexist);
+ error("name collision with physical segment");
if((perm & DMDIR) == 0)
error(Ebadarg);
@@ -249,10 +246,8 @@
if(g == nil){
if(xfree < 0)
xfree = x;
- } else {
- if(strcmp(g->name, name) == 0)
- error(Eexist);
- }
+ } else if(strcmp(g->name, name) == 0)
+ error(Eexist);
}
if(xfree < 0)
error("too many global segments");
@@ -269,7 +264,6 @@
c->qid.type = QTDIR;
c->qid.vers = 0;
c->mode = openmode(omode);
- c->mode = OWRITE;
return c;
}
@@ -330,13 +324,15 @@
va = va&~(BY2PG-1);
if(va == 0 || top > USTKTOP || top <= va)
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(!iseve())
error(Eperm);
- g->s = fixedseg(va, len);
+ g->s = fixedseg(va, len/BY2PG);
} else
- g->s = newseg(SG_SHARED, va, len);
+ g->s = newseg(SG_SHARED, va, len/BY2PG);
} else
error(Ebadctl);
free(cb);
@@ -359,22 +355,27 @@
if(c->qid.type == QTDIR)
error(Eperm);
+ d = nil;
g = getgseg(c);
if(waserror()){
+ free(d);
putgseg(g);
nexterror();
}
-
if(strcmp(g->uid, up->user) && !iseve())
error(Eperm);
d = smalloc(sizeof(Dir)+n);
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);
poperror();
- free(d);
return n;
}
@@ -399,13 +400,12 @@
* called by segattach()
*/
static Segment*
-globalsegattach(Proc *p, char *name)
+globalsegattach(char *name)
{
int x;
Globalseg *g;
Segment *s;
- g = nil;
if(waserror()){
unlock(&globalseglock);
nexterror();
@@ -414,19 +414,16 @@
for(x = 0; x < nelem(globalseg); x++){
g = globalseg[x];
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);
s = g->s;
if(s == nil)
error("global segment not assigned a virtual address");
- if(isoverlap(p, s->base, s->top - s->base) != nil)
- error("overlaps existing segment");
incref(s);
unlock(&globalseglock);
poperror();
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -389,7 +389,7 @@
struct Physseg
{
- ulong attr; /* Segment attributes */
+ int attr; /* Segment attributes */
char *name; /* Attach name */
uintptr pa; /* Physical address */
uintptr size; /* Maximum segment size in bytes */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -140,7 +140,7 @@
void isdir(Chan*);
int iseve(void);
int islo(void);
-Segment* isoverlap(Proc*, uintptr, uintptr);
+Segment* isoverlap(uintptr, uintptr);
Physseg* findphysseg(char*);
void ixsummary(void);
void kickpager(void);
@@ -309,7 +309,7 @@
void schedinit(void);
void (*screenputs)(char*, int);
long seconds(void);
-uintptr segattach(Proc*, ulong, char *, uintptr, uintptr);
+uintptr segattach(int, char *, uintptr, uintptr);
void segclock(uintptr);
long segio(Segio*, Segment*, void*, long, vlong, int);
void segpage(Segment*, Page*);
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -27,7 +27,7 @@
QLock ireclaim; /* mutex on reclaiming free images */
}imagealloc;
-Segment* (*_globalsegattach)(Proc*, char*);
+Segment* (*_globalsegattach)(char*);
void
initseg(void)
@@ -533,7 +533,7 @@
}
Segment*
-isoverlap(Proc *p, uintptr va, uintptr len)
+isoverlap(uintptr va, uintptr len)
{
int i;
Segment *ns;
@@ -541,7 +541,7 @@
newtop = va+len;
for(i = 0; i < NSEG; i++) {
- ns = p->seg[i];
+ ns = up->seg[i];
if(ns == nil)
continue;
if((newtop > ns->base && newtop <= ns->top) ||
@@ -590,7 +590,7 @@
}
uintptr
-segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
+segattach(int attr, char *name, uintptr va, uintptr len)
{
int sno;
Segment *s, *os;
@@ -600,7 +600,7 @@
error(Ebadarg);
for(sno = 0; sno < NSEG; sno++)
- if(p->seg[sno] == nil && sno != ESEG)
+ if(up->seg[sno] == nil && sno != ESEG)
break;
if(sno == NSEG)
@@ -611,9 +611,13 @@
* same name
*/
if(_globalsegattach != nil){
- s = (*_globalsegattach)(p, name);
+ s = (*_globalsegattach)(name);
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;
}
}
@@ -634,7 +638,7 @@
* map the zero page.
*/
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;
if(len >= va)
error(Enovmem);
@@ -646,7 +650,7 @@
if(va == 0 || (va+len) > USTKTOP || (va+len) < va)
error(Ebadarg);
- if(isoverlap(p, va, len) != nil)
+ if(isoverlap(va, len) != nil)
error(Esoverlap);
ps = findphysseg(name);
@@ -661,7 +665,7 @@
s = newseg(attr, va, len/BY2PG);
s->pseg = ps;
- p->seg[sno] = s;
+ up->seg[sno] = s;
return va;
}
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -429,7 +429,7 @@
tstk = s->base;
if(tstk <= USTKSIZE)
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);
/*
@@ -785,12 +785,12 @@
uintptr
syssegattach(va_list list)
{
- ulong attr;
+ int attr;
char *name;
uintptr va;
ulong len;
- attr = va_arg(list, ulong);
+ attr = va_arg(list, int);
name = va_arg(list, char*);
va = va_arg(list, uintptr);
len = va_arg(list, ulong);
@@ -800,7 +800,7 @@
free(name);
nexterror();
}
- va = segattach(up, attr, name, va, len);
+ va = segattach(attr, name, va, len);
free(name);
poperror();
return va;