shithub: front

Download patch

ref: 0217e153d7c788468f1cd30f2177246a39f399b5
parent: 1cf9125d092180931e81da35066bd8876d880d46
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():
--