git: 9front

Download patch

ref: 157ad54c8f91bf7469176c689b9a99aa531a7af0
parent: 30a34b501c28bd85b01d8f1452522cfd6ffb4b32
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Jul 5 07:33:35 EDT 2025

kernel: don't use smalloc() for ptealloc()

We dont want the fault handler to sleep holding the
segment lock when running out of kernel memory for
allocating the PTE structures.

So make ptealloc() return nil instead, and let
fault() release the Segment lock while waiting.

For sysrfork(), we can fail immediately if we run
ouf of memory allocating PTE's.

Move freepte() code into putseg().

Now segpage() can error(), so handle the in the
caller (devsegment).

--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -366,8 +366,13 @@
 				if(!iseve())
 					error(Eperm);
 				s = newseg(SG_STICKY, va, len/BY2PG);
+				if(waserror()){
+					putseg(s);
+					nexterror();
+				}
 				for(; va < s->top; va += BY2PG)
 					segpage(s, newpage(1, nil, va));
+				poperror();
 				g->s = s;
 			} else
 				g->s = newseg(SG_SHARED, va, len/BY2PG);
@@ -499,7 +504,6 @@
 			}
 			f = &p->next;
 		}
-
 		if(i != len){
 			if(h != nil){
 				t->next = palloc.head;
@@ -517,9 +521,14 @@
 			p->va = va;
 			va += BY2PG;
 			p->modref = 0;
-			settxtflush(p, 1);
 			zeropage(p);
+			if(waserror()){
+				while(++p <= l)
+					freepages(p, p, 1);
+				nexterror();
+			}
 			segpage(s, p);
+			poperror();
 		} while(p != l);
 
 		poperror();
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -78,7 +78,7 @@
 	}
 	qunlock(s);
 
-	new = newpage(0, 0, addr);
+	new = newpage(0, nil, addr);
 	k = kmap(new);
 	c = image->c;
 	while(waserror()) {
@@ -143,8 +143,18 @@
 	addr &= ~(BY2PG-1);
 	soff = addr-s->base;
 	pte = &s->map[soff/PTEMAPMEM];
-	if((etp = *pte) == nil)
-		*pte = etp = ptealloc();
+	if((etp = *pte) == nil){
+		etp = ptealloc();
+		if(etp == nil){
+			qunlock(s);
+			if(!waserror()){
+				resrcwait("no memory for ptealloc");
+				poperror();
+			}
+			return -1;
+		}
+		*pte = etp;
+	}
 
 	pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
 	if(pg < etp->first)
--- a/sys/src/9/port/page.c
+++ b/sys/src/9/port/page.c
@@ -358,72 +358,6 @@
 	}
 }
 
-Pte*
-ptecpy(Pte *old)
-{
-	Pte *new;
-	Page **src, **dst, *entry;
-
-	new = ptealloc();
-	dst = &new->pages[old->first-old->pages];
-	new->first = dst;
-	for(src = old->first; src <= old->last; src++, dst++)
-		if((entry = *src) != nil) {
-			if(onswap(entry))
-				dupswap(entry);
-			else
-				incref(entry);
-			new->last = dst;
-			*dst = entry;
-		}
-
-	return new;
-}
-
-Pte*
-ptealloc(void)
-{
-	Pte *new;
-
-	new = smalloc(sizeof(Pte));
-	new->first = &new->pages[PTEPERTAB];
-	new->last = new->pages;
-	return new;
-}
-
-void
-freepte(Segment*, Pte *p)
-{
-	Page **pg, **pe, *entry;
-	Page *fh, *ft;
-	ulong np;
-
-	np = 0;
-	fh = ft = nil;
-	pg = p->first;
-	pe = p->last;
-	while(pg <= pe){
-		if((entry = *pg) != nil){
-			if(onswap(entry))
-				putswap(entry);
-			else {
-				entry = deadpage(entry);
-				if(entry != nil){
-					if(fh != nil)
-						ft->next = entry;
-					else
-						fh = entry;
-					ft = entry;
-					np++;
-				}
-			}
-		}
-		pg++;
-	}
-	freepages(fh, ft, np);
-	free(p);
-}
-
 void
 zeroprivatepages(void)
 {
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -128,7 +128,6 @@
 void		freenote(Note*);
 void		freenotes(Proc*);
 void		freepages(Page*, Page*, ulong);
-void		freepte(Segment*, Pte*);
 void		getcolor(ulong, ulong*, ulong*, ulong*);
 uintptr		getmalloctag(void*);
 uintptr		getrealloctag(void*);
@@ -268,7 +267,6 @@
 extern void	(*proctrace)(Proc*, int, vlong); 
 void		procwired(Proc*, int);
 Pte*		ptealloc(void);
-Pte*		ptecpy(Pte*);
 int		pullblock(Block**, int);
 Block*		pullupblock(Block*, int);
 Block*		pullupqueue(Queue*, int);
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -91,7 +91,6 @@
 void
 putseg(Segment *s)
 {
-	Pte **pte, **emap;
 	Image *i;
 
 	if(s == nil)
@@ -125,11 +124,44 @@
 	assert(s->sema.next == &s->sema);
 
 	if(s->mapsize > 0){
+		Pte **pte, **emap;
+		Page *fh, *ft;
+		ulong np;
+
+		np = 0;
+		fh = ft = nil;
+
 		emap = &s->map[s->mapsize];
 		for(pte = s->map; pte < emap; pte++){
-			if(*pte != nil)
-				freepte(s, *pte);
+			Page **pg, **pe, *entry;
+
+			if(*pte == nil)
+				continue;
+			pg = (*pte)->first;
+			pe = (*pte)->last;
+			while(pg <= pe){
+				entry = *pg++;
+				if(entry == nil)
+					continue;
+				if(onswap(entry)){
+					putswap(entry);
+					continue;
+				}
+				entry = deadpage(entry);
+				if(entry == nil)
+					continue;
+				if(fh != nil)
+					ft->next = entry;
+				else
+					fh = entry;
+				ft = entry;
+				np++;
+			}
+			free(*pte);
 		}
+
+		freepages(fh, ft, np);
+
 		if(s->map != s->ssegmap)
 			free(s->map);
 	}
@@ -140,22 +172,37 @@
 	free(s);
 }
 
-void
-relocateseg(Segment *s, uintptr offset)
+Pte*
+ptealloc(void)
 {
-	Pte **pte, **emap;
-	Page **pg, **pe;
+	Pte *new;
 
-	emap = &s->map[s->mapsize];
-	for(pte = s->map; pte < emap; pte++) {
-		if(*pte == nil)
+	new = malloc(sizeof(Pte));
+	if(new != nil){
+		new->first = &new->pages[PTEPERTAB];
+		new->last = new->pages;
+	}
+	return new;
+}
+
+static Pte*
+ptecpy(Pte *new, Pte *old)
+{
+	Page **src, **dst, *entry;
+
+	dst = &new->pages[old->first-old->pages];
+	new->first = dst;
+	for(src = old->first; src <= old->last; src++, dst++){
+		if((entry = *src) == nil)
 			continue;
-		pe = (*pte)->last;
-		for(pg = (*pte)->first; pg <= pe; pg++) {
-			if(!pagedout(*pg))
-				(*pg)->va += offset;
-		}
+		if(onswap(entry))
+			dupswap(entry);
+		else
+			incref(entry);
+		new->last = dst;
+		*dst = entry;
 	}
+	return new;
 }
 
 Segment*
@@ -206,9 +253,18 @@
 		incref(s->image);
 		break;
 	}
-	for(i = 0; i < s->mapsize; i++)
-		if((pte = s->map[i]) != nil)
-			n->map[i] = ptecpy(pte);
+	for(i = 0; i < s->mapsize; i++){
+		if(s->map[i] != nil){
+			pte = ptealloc();
+			if(pte == nil){
+				qunlock(s);
+				poperror();
+				putseg(n);
+				error(Enomem);
+			}
+			n->map[i] = ptecpy(pte, s->map[i]);
+		}
+	}
 	n->used = s->used;
 	n->swapped = s->swapped;
 	n->flushme = s->flushme;
@@ -225,6 +281,10 @@
 	return s;
 }
 
+/*
+ *  segpage inserts Page p into Segmnet s.
+ *  on error, calls putpage() on p.
+ */
 void
 segpage(Segment *s, Page *p)
 {
@@ -235,13 +295,20 @@
 	qlock(s);
 	if(p->va < s->base || p->va >= s->top || s->mapsize == 0)
 		panic("segpage");
-
 	soff = p->va - s->base;
 	pte = &s->map[soff/PTEMAPMEM];
-	if((etp = *pte) == nil)
-		*pte = etp = ptealloc();
+	if((etp = *pte) == nil){
+		etp = ptealloc();
+		if(etp == nil){
+			qunlock(s);
+			putpage(p);
+			error(Enomem);
+		}
+		*pte = etp;
+	}
 	pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
 	assert(*pg == nil);
+	settxtflush(p, s->flushme);
 	*pg = p;
 	s->used++;
 	if(pg < etp->first)
@@ -251,6 +318,25 @@
 	qunlock(s);
 }
 
+void
+relocateseg(Segment *s, uintptr offset)
+{
+	Pte **pte, **emap;
+	Page **pg, **pe;
+
+	emap = &s->map[s->mapsize];
+	for(pte = s->map; pte < emap; pte++) {
+		if(*pte == nil)
+			continue;
+		pe = (*pte)->last;
+		for(pg = (*pte)->first; pg <= pe; pg++) {
+			if(!pagedout(*pg))
+				(*pg)->va += offset;
+		}
+	}
+}
+
+
 Image*
 attachimage(Chan *c)
 {
@@ -801,7 +887,6 @@
 	poperror();
 	return ps;
 }
-
 
 enum {
 	/* commands to segmentioproc */
--- a/sys/src/9/port/userinit.c
+++ b/sys/src/9/port/userinit.c
@@ -27,6 +27,8 @@
 	Page *p;
 
 	spllo();
+	if(waserror())
+		panic("proc0: %s", up->errstr);
 
 	up->pgrp = newpgrp();
 	up->egrp = smalloc(sizeof(Egrp));
@@ -48,13 +50,12 @@
 	 */
 	up->seg[SSEG] = newseg(SG_STACK | SG_NOEXEC, USTKTOP-USTKSIZE, USTKSIZE / BY2PG);
 	up->seg[TSEG] = newseg(SG_TEXT | SG_RONLY, UTZERO, 1);
-	p = newpage(1, 0, UTZERO);
+	up->seg[TSEG]->flushme = 1;
+	p = newpage(1, nil, UTZERO);
 	k = kmap(p);
 	memmove((void*)VA(k), initcode, sizeof(initcode));
 	kunmap(k);
-	settxtflush(p, 1);
 	segpage(up->seg[TSEG], p);
-	up->seg[TSEG]->flushme = 1;
 
 	/*
 	 * Become a user process.
@@ -66,6 +67,8 @@
 	procsetup(up);
 
 	flushmmu();
+
+	poperror();
 
 	/*
 	 * init0():
--