shithub: riscv

Download patch

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;