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():
--
⑨