ref: afa2d8b552a269d1bfdd0125f76c148575c6c194
parent: 81f4d1d7fc259f1e05dd101586fe98b7c38c211f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Jun 16 14:35:36 EDT 2025
kernel: fix deadlock between sysexec() and killbig() (thanks ori) During exec, we used to hold up->seglock while the stack is being demand paged in. In a low-memory situation, this leads to deadlock because killbig() is calling procpagecount() for each process to determine is physical memory usage. This function acqires p->seglock. So killbig() can be stuck once it hits a process that is starving on memory during faulting in its stack. This change makes sysexec release the seglock during its its stack preparation phase, and re-aquire it once we enter the "committ" phase (freeing our old stack).
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -443,15 +443,9 @@
*/
qlock(&up->seglock);
if(waserror()){
- s = up->seg[ESEG];
- if(s != nil){
- up->seg[ESEG] = nil;
- putseg(s);
- }
qunlock(&up->seglock);
nexterror();
}
-
s = up->seg[SSEG];
do {
tstk = s->base;
@@ -459,7 +453,18 @@
error(Enovmem);
} while((s = isoverlap(tstk-USTKSIZE, USTKSIZE)) != nil);
up->seg[ESEG] = newseg(SG_STACK | SG_NOEXEC, tstk-USTKSIZE, USTKSIZE/BY2PG);
+ qunlock(&up->seglock);
+ if(waserror()){
+ qlock(&up->seglock);
+ s = up->seg[ESEG];
+ if(s != nil){
+ up->seg[ESEG] = nil;
+ putseg(s);
+ }
+ nexterror();
+ }
+
/*
* Args: pass 2: assemble; the pages will be faulted in
*/
@@ -520,6 +525,9 @@
* Free old memory.
* Special segments are maintained across exec
*/
+ poperror();
+ qlock(&up->seglock);
+
for(i = SSEG; i <= BSEG; i++) {
s = up->seg[i];
if(s != nil) {
@@ -576,10 +584,14 @@
* Move the stack
*/
s = up->seg[ESEG];
+ if(s == nil)
+ error(Egreg);
up->seg[ESEG] = nil;
+ qlock(s);
s->base = USTKTOP-USTKSIZE;
s->top = USTKTOP;
relocateseg(s, USTKTOP-tstk);
+ qunlock(s);
up->seg[SSEG] = s;
qunlock(&up->seglock);
poperror(); /* seglock */
@@ -894,8 +906,8 @@
qunlock(s);
error(Ebadarg);
}
- up->seg[i] = nil;
qunlock(s);
+ up->seg[i] = nil;
putseg(s);
qunlock(&up->seglock);
poperror();
--
⑨