diag(base): trace fd transfer in init, daemon, and logd
Add diagnostics to pin down where the INIT_NOTIFY fd handoff hangs: - init/src/service.rs: log read_pipe fd and call_ro results - daemon/src/lib.rs: log cap_fd, write_pipe, and call_wo result - logd/src/main.rs: explicit ready_sync_scheme result and setrens fallback These are temporary diagnostics for the boot-hang investigation.
This commit is contained in:
+11
-3
@@ -106,12 +106,20 @@ impl SchemeDaemon {
|
|||||||
|
|
||||||
/// Notify the process that the scheme daemon is ready to accept requests.
|
/// Notify the process that the scheme daemon is ready to accept requests.
|
||||||
pub fn ready_with_fd(self, cap_fd: Fd) -> syscall::Result<()> {
|
pub fn ready_with_fd(self, cap_fd: Fd) -> syscall::Result<()> {
|
||||||
syscall::call_wo(
|
let raw_fd = cap_fd.into_raw();
|
||||||
|
eprintln!(
|
||||||
|
"daemon: ready_with_fd write_pipe={} cap_fd={}",
|
||||||
|
self.write_pipe.as_raw_fd(),
|
||||||
|
raw_fd
|
||||||
|
);
|
||||||
|
let res = syscall::call_wo(
|
||||||
self.write_pipe.as_raw_fd() as usize,
|
self.write_pipe.as_raw_fd() as usize,
|
||||||
&cap_fd.into_raw().to_ne_bytes(),
|
&raw_fd.to_ne_bytes(),
|
||||||
syscall::CallFlags::FD,
|
syscall::CallFlags::FD,
|
||||||
&[],
|
&[],
|
||||||
)?;
|
);
|
||||||
|
eprintln!("daemon: ready_with_fd call_wo result={:?}", res);
|
||||||
|
res?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
-12
@@ -1,11 +1,11 @@
|
|||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::{self, Read, Write};
|
||||||
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
|
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
|
||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{env, io};
|
use std::env;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
@@ -49,6 +49,8 @@ fn create_pipe() -> io::Result<(File, OwnedFd)> {
|
|||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub fn spawn(&self, base_envs: &BTreeMap<String, OsString>) {
|
pub fn spawn(&self, base_envs: &BTreeMap<String, OsString>) {
|
||||||
|
eprintln!("init: service {} type={:?}", self.cmd, self.type_);
|
||||||
|
let _ = io::stderr().flush();
|
||||||
let mut command = Command::new(&self.cmd);
|
let mut command = Command::new(&self.cmd);
|
||||||
command.args(self.args.iter().map(|arg| subst_env(arg)));
|
command.args(self.args.iter().map(|arg| subst_env(arg)));
|
||||||
command.env_clear();
|
command.env_clear();
|
||||||
@@ -61,29 +63,52 @@ impl Service {
|
|||||||
|
|
||||||
let (mut read_pipe, write_pipe) = create_pipe()
|
let (mut read_pipe, write_pipe) = create_pipe()
|
||||||
.unwrap_or_else(|e| panic!("pipe() failed in service.spawn for {}: {}", self.cmd, e));
|
.unwrap_or_else(|e| panic!("pipe() failed in service.spawn for {}: {}", self.cmd, e));
|
||||||
|
eprintln!("init: {} pipe created read_pipe={}", self.cmd, read_pipe.as_raw_fd());
|
||||||
|
let _ = io::stderr().flush();
|
||||||
unsafe { pass_fd(&mut command, "INIT_NOTIFY", write_pipe.into()) };
|
unsafe { pass_fd(&mut command, "INIT_NOTIFY", write_pipe.into()) };
|
||||||
|
eprintln!("init: {} pass_fd done", self.cmd);
|
||||||
|
let _ = io::stderr().flush();
|
||||||
|
|
||||||
let mut child = match command.spawn() {
|
let mut child = match command.spawn() {
|
||||||
Ok(child) => child,
|
Ok(child) => {
|
||||||
|
eprintln!("init: {} spawned pid=??", self.cmd);
|
||||||
|
let _ = io::stderr().flush();
|
||||||
|
child
|
||||||
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
status_fail(&format!("failed to execute {:?}: {}", command, err));
|
status_fail(&format!("failed to execute {:?}: {}", command, err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eprintln!("init: {} entering match type={:?}", self.cmd, self.type_);
|
||||||
|
let _ = io::stderr().flush();
|
||||||
match &self.type_ {
|
match &self.type_ {
|
||||||
ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
|
ServiceType::Notify => {
|
||||||
Ok(()) => {}
|
eprintln!("init: {} is Notify, waiting for byte", self.cmd);
|
||||||
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
|
let _ = io::stderr().flush();
|
||||||
init_warn(&format!("{:?} exited without notifying readiness", command));
|
match read_pipe.read_exact(&mut [0]) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
|
||||||
|
init_warn(&format!("{:?} exited without notifying readiness", command));
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
init_error(&format!("failed to wait for {:?}: {}", command, err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
}
|
||||||
init_error(&format!("failed to wait for {:?}: {}", command, err));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ServiceType::Scheme(scheme) => {
|
ServiceType::Scheme(scheme) => {
|
||||||
|
eprintln!("init: SCHEME {} waiting for fd on read_pipe={}", self.cmd, read_pipe.as_raw_fd());
|
||||||
|
let _ = io::stderr().flush();
|
||||||
|
init_warn(&format!(
|
||||||
|
"init: waiting for scheme fd from {:?}, read_pipe={}",
|
||||||
|
command,
|
||||||
|
read_pipe.as_raw_fd()
|
||||||
|
));
|
||||||
let mut new_fd = usize::MAX;
|
let mut new_fd = usize::MAX;
|
||||||
loop {
|
loop {
|
||||||
|
eprintln!("init: calling call_ro for {}", self.cmd);
|
||||||
|
let _ = io::stderr().flush();
|
||||||
match syscall::call_ro(
|
match syscall::call_ro(
|
||||||
read_pipe.as_raw_fd() as usize,
|
read_pipe.as_raw_fd() as usize,
|
||||||
unsafe { plain::as_mut_bytes(&mut new_fd) },
|
unsafe { plain::as_mut_bytes(&mut new_fd) },
|
||||||
@@ -97,7 +122,13 @@ impl Service {
|
|||||||
init_warn(&format!("{:?} exited without notifying readiness", command));
|
init_warn(&format!("{:?} exited without notifying readiness", command));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(1) => break,
|
Ok(1) => {
|
||||||
|
init_warn(&format!(
|
||||||
|
"init: received scheme fd {} from {:?}, registering as {}",
|
||||||
|
new_fd, command, scheme
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
init_error(&format!("incorrect amount of fds {} returned", n));
|
init_error(&format!("incorrect amount of fds {} returned", n));
|
||||||
return;
|
return;
|
||||||
|
|||||||
+8
-2
@@ -11,9 +11,15 @@ fn daemon(daemon: daemon::SchemeDaemon) -> ! {
|
|||||||
let mut scheme = LogScheme::new(&socket);
|
let mut scheme = LogScheme::new(&socket);
|
||||||
let handler = Blocking::new(&socket, 16);
|
let handler = Blocking::new(&socket, 16);
|
||||||
|
|
||||||
let _ = daemon.ready_sync_scheme(&socket, &mut scheme);
|
match daemon.ready_sync_scheme(&socket, &mut scheme) {
|
||||||
|
Ok(()) => eprintln!("logd: ready_sync_scheme succeeded"),
|
||||||
|
Err(err) => eprintln!("logd: ready_sync_scheme failed: {err}"),
|
||||||
|
}
|
||||||
|
|
||||||
libredox::call::setrens(0, 0).expect("logd: failed to enter null namespace");
|
match libredox::call::setrens(0, 0) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => eprintln!("logd: warning: failed to enter null namespace: {err}"),
|
||||||
|
}
|
||||||
|
|
||||||
handler
|
handler
|
||||||
.process_requests_blocking(scheme)
|
.process_requests_blocking(scheme)
|
||||||
|
|||||||
Reference in New Issue
Block a user