bug pass: whole console lines, a quiet SCI, an honest reserve warning

- schinit, schinitd and vgpud build every message from pieces, one
  write() each, so a job starting on another CPU landed mid-line:
  "schinitd: starting vgpud: os.schos.resolvconfno virtio-gpu on this
  machine". They now collect a line and write it at the newline;
  resolvconf's verbose line is one write with its prefix.
- The ACPI SCI registers IRQ_QUIET. A desktop's SCI never fires, and the
  poller took two seconds of silence for a misrouted line ("irq 9:
  nothing has arrived on it") and called the handler every tick. A line
  is only exempt while every handler on it is quiet.
- The loader claims each segment from where the last one's claim ended,
  so two segments sharing a page no longer ask for it twice. When a
  claim is still refused, it names the memory-map entries in the way.
- Stale divesymlink() declaration gone; the kernel.md struct table
  re-measured (inode, buf and file pools grow from slabs now).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-23 16:03:33 +02:00
commit e659c6b187
10 changed files with 184 additions and 25 deletions

View file

@ -83,10 +83,40 @@ ends_with(const char *s, const char *suffix)
return seq(s + ls - lf, suffix);
}
// Whole lines, in one write() each.
//
// Every message here is assembled from pieces -- a prefix, a job's label, a
// number -- and each piece used to be its own write(). The console keeps one
// write() together, but nothing keeps two of them together, so a job starting
// on another CPU landed in the middle of the line: "schinitd: starting vgpud:
// os.schos.resolvconfno virtio-gpu on this machine" was this process and
// vgpud taking turns a word at a time. The pieces now collect here and go out
// at the newline.
static char lbuf[512];
static int lbn;
static void
lflush(void)
{
if (lbn)
write(1, lbuf, lbn);
lbn = 0;
}
static void
emit(const char *s, int n)
{
for (int i = 0; i < n; i++) {
lbuf[lbn++] = s[i];
if (s[i] == '\n' || lbn == (int)sizeof lbuf)
lflush();
}
}
static void
out(const char *s)
{
write(1, (void *)s, slen(s));
emit(s, slen(s));
}
// How the machine was booted, read once.
@ -139,7 +169,7 @@ static void
vout(const char *s)
{
if (verbose_boot)
write(1, (void *)s, slen(s));
emit(s, slen(s));
}
static void
@ -626,14 +656,17 @@ main(void)
h.reserved = 0;
if (write(sock, &h, sizeof(h)) != sizeof(h)) {
out("schinitd: no channel to pid 1\n");
lflush();
exit();
}
if (read(sock, &h, sizeof(h)) != sizeof(h) || h.op != SCHINIT_WELCOME) {
out("schinitd: pid 1 did not answer\n");
lflush();
exit();
}
if (h.proto != SCHINIT_PROTO) {
out("schinitd: protocol mismatch with pid 1\n");
lflush();
exit();
}
@ -742,7 +775,8 @@ main(void)
// pinging -- which it has, because it is no longer talking to us.
if (pr > 0 && (pf.revents & (POLLHUP | POLLERR | POLLNVAL))) {
out("schinitd: channel closed; this supervisor has been replaced\n");
exit();
lflush();
exit();
}
if (pr > 0 && (pf.revents & POLLIN)) {
@ -752,7 +786,8 @@ main(void)
// PID 1 closed the channel. It is the one process that cannot
// have gone away, so this means we are being replaced.
out("schinitd: channel closed\n");
exit();
lflush();
exit();
}
if (m.op == SCHINIT_PING) {
struct schinit_hello p;