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