ref: 1013893cd058fa7b8413c2aa0e55547f58187245
parent: 533c792292dfff8e7c0a22d3e565acc84866c78c
	author: cinap_lenrek <cinap_lenrek@felloff.net>
	date: Sat Aug 23 12:14:05 EDT 2025
	
kernel: make pio() interruptable, avoid copy when doing single-page I/O When we get interrupted during I/O, make pio()/fixfault() return with -1 into fault(). Then fault() checks up->procctl and handles if we got killed. Also, handle a I/O with size <= BY2PG using Dev.read instead of Dev.pread. This can avoid extra copy (for example in the case when devdrawp is on a disk).
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -17,6 +17,7 @@
 	if(up->nerrlab) {if(up->kp == 0)
postnote(up, 1, buf, NDebug);
+ up->psstate = nil;
error(s);
}
 	pprint("suicide: %s\n", buf);@@ -33,16 +34,15 @@
postnote(up, 1, buf, NDebug);
}
-static void
+static int
pio(Segment *s, uintptr addr, uintptr soff, Page **p)
 {KMap *k;
Chan *c;
int n, ask;
- uintptr o, daddr, paddr;
+ uintptr daddr, vaddr;
Page *loadrec, *new;
Image *image;
- Block *b;
retry:
loadrec = *p;
@@ -53,7 +53,7 @@
 		if(new != nil) {*p = new;
s->used++;
- return;
+ return 0;
}
ask = image->c->iounit;
@@ -64,10 +64,9 @@
daddr = soff & -ask;
if(daddr+ask > s->flen)
ask = s->flen-daddr;
- paddr = s->base + daddr;
+ vaddr = s->base + daddr;
daddr += s->fstart;
- }
-	else {			/* from a swap image */+	} else {		/* from a swap image */daddr = swapaddr(loadrec);
image = swapimage;
new = lookpage(image, daddr);
@@ -75,51 +74,75 @@
*p = new;
s->swapped--;
putswap(loadrec);
- return;
+ return 0;
}
- paddr = addr;
+ vaddr = addr;
ask = BY2PG;
}
qunlock(s);
c = image->c;
-	while(waserror()) {+	if(waserror()) {if(strcmp(up->errstr, Eintr) == 0)
- continue;
+ return -1;
faulterror(Eioload, c);
}
- b = devtab[c->type]->bread(c, ask, daddr);
-	if(waserror()){- freeblist(b);
- nexterror();
- }
-	for(o = 0; o < ask; o += BY2PG){- new = lookpage(image, daddr + o);
-		if(new != nil){- putpage(new);
- continue;
- }
- new = newpage(paddr + o, nil);
- new->daddr = daddr + o;
+	if(ask <= BY2PG) {+ new = newpage(vaddr, nil);
+ new->daddr = daddr;
k = kmap(new);
- n = ask - o;
- if(n > BY2PG)
- n = BY2PG;
- else if(n < BY2PG)
- memset((uchar*)VA(k)+n, 0, BY2PG-n);
-		if(readblist(b, (uchar*)VA(k), n, o) != n){+		if(waserror()){kunmap(k);
putpage(new);
- error(Eshort);
+ nexterror();
}
+ n = devtab[c->type]->read(c, (uchar*)VA(k), ask, daddr);
+ if(n != ask)
+ error(Eshort);
+ if(n < BY2PG)
+ memset((uchar*)VA(k)+n, 0, BY2PG-n);
kunmap(k);
settxtflush(new, s->flushme);
cachepage(new, image);
putpage(new);
+ poperror();
+	} else {+ uintptr o;
+ Block *b;
+
+ b = devtab[c->type]->bread(c, ask, daddr);
+		if(waserror()){+ freeblist(b);
+ nexterror();
+ }
+		for(o = 0; o < ask; o += BY2PG){+ new = lookpage(image, daddr + o);
+			if(new != nil){+ putpage(new);
+ continue;
+ }
+ new = newpage(vaddr + o, nil);
+ new->daddr = daddr + o;
+ k = kmap(new);
+ n = ask - o;
+ if(n > BY2PG)
+ n = BY2PG;
+ else if(n < BY2PG)
+ memset((uchar*)VA(k)+n, 0, BY2PG-n);
+			if(readblist(b, (uchar*)VA(k), n, o) != n){+ kunmap(k);
+ putpage(new);
+ error(Eshort);
+ }
+ kunmap(k);
+ settxtflush(new, s->flushme);
+ cachepage(new, image);
+ putpage(new);
+ }
+ freeblist(b);
+ poperror();
}
- freeblist(b);
poperror();
- poperror();
qlock(s);
/*
@@ -128,7 +151,7 @@
* s was unlocked
*/
if(*p != loadrec && !pagedout(*p))
- return;
+ return 0;
goto retry;
}
@@ -166,9 +189,10 @@
 		panic("fault");case SG_TEXT: /* Demand load */
- if(pagedout(*pg))
- pio(s, addr, soff, pg);
-
+		if(pagedout(*pg)){+ if(pio(s, addr, soff, pg) < 0)
+ return -1;
+ }
mmuphys = PPN((*pg)->pa) | PTERONLY | PTECACHED | PTEVALID;
(*pg)->modref = PG_REF;
break;
@@ -185,9 +209,10 @@
}
/* wet floor */
case SG_DATA: /* Demand load/pagein/copy on write */
- if(pagedout(*pg))
- pio(s, addr, soff, pg);
-
+		if(pagedout(*pg)){+ if(pio(s, addr, soff, pg) < 0)
+ return -1;
+ }
/*
* It's only possible to copy on write if
* we're the only user of the segment.
--
⑨