scheme-utils: Panic on scheme EOF

EOF used to be triggered by unmounting a scheme, but this is no longer
the case since namespaces got moved to userspace. Unmounting now only
closes the scheme root fd.
This commit is contained in:
bjorn3
2026-04-15 22:13:06 +02:00
parent a5018ca37e
commit a2bc1dd79c
7 changed files with 47 additions and 143 deletions
+2 -8
View File
@@ -71,16 +71,10 @@ fn daemon(daemon: SchemeDaemon) -> anyhow::Result<()> {
let mut readiness = ReadinessBased::new(&socket, 16);
loop {
if !readiness.read_and_process_requests(&mut *scheme.lock().unwrap())? {
break;
}
readiness.read_and_process_requests(&mut *scheme.lock().unwrap())?;
readiness.poll_all_requests(&mut *scheme.lock().unwrap())?;
if !readiness.write_responses()? {
break;
};
readiness.write_responses()?;
}
Ok(())
}
fn main() {
+6 -15
View File
@@ -96,12 +96,9 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
readiness_based
.poll_all_requests(&mut device)
.expect("ac97d: failed to poll requests");
if !readiness_based
readiness_based
.write_responses()
.expect("ac97d: failed to write to socket")
{
break;
}
.expect("ac97d: failed to write to socket");
/*
let next_read = device_irq.next_read();
@@ -111,18 +108,12 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
*/
}
Source::Scheme => {
if !readiness_based
readiness_based
.read_and_process_requests(&mut device)
.expect("ac97d: failed to read from socket")
{
break;
}
if !readiness_based
.expect("ac97d: failed to read from socket");
readiness_based
.write_responses()
.expect("ac97d: failed to write to socket")
{
break;
}
.expect("ac97d: failed to write to socket");
/*
let next_read = device.borrow().next_read();
+6 -15
View File
@@ -101,12 +101,9 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
readiness_based
.poll_all_requests(&mut device)
.expect("ihdad: failed to poll requests");
if !readiness_based
readiness_based
.write_responses()
.expect("ihdad: failed to write to socket")
{
break;
}
.expect("ihdad: failed to write to socket");
/*
let next_read = device_irq.next_read();
@@ -116,18 +113,12 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
*/
}
Source::Scheme => {
if !readiness_based
readiness_based
.read_and_process_requests(&mut device)
.expect("ihdad: failed to read from socket")
{
break;
}
if !readiness_based
.expect("ihdad: failed to read from socket");
readiness_based
.write_responses()
.expect("ihdad: failed to write to socket")
{
break;
}
.expect("ihdad: failed to write to socket");
/*
let next_read = device.borrow().next_read();
+6 -15
View File
@@ -87,12 +87,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
readiness_based
.poll_all_requests(&mut device)
.expect("sb16d: failed to poll requests");
if !readiness_based
readiness_based
.write_responses()
.expect("sb16d: failed to write to socket")
{
break;
}
.expect("sb16d: failed to write to socket");
/*
let next_read = device_irq.next_read();
@@ -102,18 +99,12 @@ fn daemon(daemon: daemon::Daemon) -> ! {
*/
}
Source::Scheme => {
if !readiness_based
readiness_based
.read_and_process_requests(&mut device)
.expect("sb16d: failed to read from socket")
{
break;
}
if !readiness_based
.expect("sb16d: failed to read from socket");
readiness_based
.write_responses()
.expect("sb16d: failed to write to socket")
{
break;
}
.expect("sb16d: failed to write to socket");
}
}
}
+13 -67
View File
@@ -75,7 +75,7 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
daemon.ready();
// Create event listener for both files
let mut event_queue = EventQueue::<EventSource>::new()
let event_queue = EventQueue::<EventSource>::new()
.map_err(|e| anyhow::anyhow!("failed to create event queue: {e}"))?;
event_queue
.subscribe(
@@ -108,96 +108,42 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
libredox::call::setrens(0, 0)?;
// EOF flags
let mut chan_eof = false;
let mut shm_eof = false;
let mut uds_stream_eof = false;
let mut uds_dgram_eof = false;
while !(chan_eof && shm_eof && uds_stream_eof && uds_dgram_eof) {
let Some(event_res) = event_queue.next() else {
break;
};
let event = event_res.map_err(|e| anyhow::anyhow!("error occured in event queue: {e}"))?;
loop {
let event = event_queue
.next_event()
.map_err(|e| anyhow::anyhow!("error occured in event queue: {e}"))?;
match event.user_data {
EventSource::ChanSocket => {
// Channel scheme
if !chan_eof {
// 1. Read and process requests
if !chan_handler.read_and_process_requests(&mut chan)? {
chan_eof = true;
}
}
// 2. Poll all blocking requests
chan_handler.read_and_process_requests(&mut chan)?;
chan_handler
.poll_all_requests(&mut chan)
.map_err(|e| anyhow::anyhow!("error occured in poll_all_requests: {e}"))?;
// 3. Write responses
// write_responses returns a Result<bool>, but currently only returns true.
if !chan_handler.write_responses()? {
chan_eof = true;
}
chan_handler.write_responses()?;
}
EventSource::ShmSocket => {
// Shared memory scheme
if !shm_eof {
// 1. Read and process requests
if !shm_handler.read_and_process_requests(&mut shm)? {
shm_eof = true;
}
}
shm_handler.read_and_process_requests(&mut shm)?;
// shm is not a blocking scheme
// 2. Write responses
// write_responses returns a Result<bool>, but currently only returns true.
if !shm_handler.write_responses()? {
shm_eof = true;
}
shm_handler.write_responses()?;
}
EventSource::UdsStreamSocket => {
// Unix Domain Socket Stream scheme
if !uds_stream_eof {
// 1. Read and process requests
if !uds_stream_handler.read_and_process_requests(&mut uds_stream)? {
uds_stream_eof = true;
}
}
// 2. Poll all blocking requests
uds_stream_handler.read_and_process_requests(&mut uds_stream)?;
uds_stream_handler
.poll_all_requests(&mut uds_stream)
.map_err(|e| anyhow::anyhow!("error occured in poll_all_requests: {e}"))?;
// 3. Write responses
// write_responses returns a Result<bool>, but currently only returns true.
if !uds_stream_handler.write_responses()? {
uds_stream_eof = true;
}
uds_stream_handler.write_responses()?;
}
EventSource::UdsDgramSocket => {
// Unix Domain Socket Dgram scheme
if !uds_dgram_eof {
// 1. Read and process requests
if !uds_dgram_handler.read_and_process_requests(&mut uds_dgram)? {
uds_dgram_eof = true;
}
}
// 2. Poll all blocking requests
uds_dgram_handler.read_and_process_requests(&mut uds_dgram)?;
uds_dgram_handler
.poll_all_requests(&mut uds_dgram)
.map_err(|e| anyhow::anyhow!("error occured in poll_all_requests: {e}"))?;
// 3. Write responses
// write_responses returns a Result<bool>, but currently only returns true.
if !uds_dgram_handler.write_responses()? {
uds_dgram_eof = true;
}
uds_dgram_handler.write_responses()?;
}
}
}
Ok(())
}
+4 -15
View File
@@ -95,26 +95,15 @@ fn scan_requests(
handler: &mut ReadinessBased<'_>,
scheme: &mut PtyScheme,
) -> libredox::error::Result<()> {
// 1. Read and process requests
if !handler
handler
.read_and_process_requests(scheme)
.expect("pty: failed to read from socket")
{
panic!("pty: channel EOF")
}
// 2. Poll all blocking requests
.expect("pty: failed to read from socket");
handler
.poll_all_requests(scheme)
.expect("pty: error occured in poll_all_requests");
// 3. Write responses
if !handler
handler
.write_responses()
.expect("pty: failed to write to socket")
{
panic!("pty: channel EOF")
}
.expect("pty: failed to write to socket");
Ok(())
}
+10 -8
View File
@@ -31,15 +31,16 @@ impl<'sock> ReadinessBased<'sock> {
state: SchemeState::new(),
}
}
pub fn read_and_process_requests(&mut self, scheme: &mut impl SchemeSync) -> Result<bool> {
pub fn read_and_process_requests(&mut self, scheme: &mut impl SchemeSync) -> Result<()> {
assert!(self.requests_read.is_empty());
match self
.socket
.read_requests(&mut self.requests_read, SignalBehavior::Interrupt)
{
// TODO: write ECANCELED or similar for everything in self.states?
Ok(()) if self.requests_read.is_empty() => return Ok(false), // EOF
Ok(()) if self.requests_read.is_empty() => {
unreachable!("blocking scheme read failed to read anything");
}
Ok(())
| Err(Error {
errno: errno::EINTR | errno::EWOULDBLOCK | errno::EAGAIN,
@@ -113,7 +114,7 @@ impl<'sock> ReadinessBased<'sock> {
self.responses_to_write.push_back(resp);
}
Ok(true)
Ok(())
}
// TODO: Doesn't scale. Instead, provide an API for some form of queue.
// TODO: panic if id isn't present?
@@ -175,17 +176,18 @@ impl<'sock> ReadinessBased<'sock> {
self.ready_queue.extend(self.states.keys().copied());
self.poll_ready_requests(scheme)
}
pub fn write_responses(&mut self) -> Result<bool> {
pub fn write_responses(&mut self) -> Result<()> {
match self
.socket
.write_responses(&mut self.responses_to_write, SignalBehavior::Restart)
{
// TODO: write ECANCELED or similar for everything in self.states?
//Ok(()) if !self.responses_to_write.is_empty() => Ok(false), // EOF, FIXME
Ok(()) if !self.responses_to_write.is_empty() => {
panic!("failed to write all scheme responses");
}
Ok(())
| Err(Error {
errno: errno::EINTR | errno::EWOULDBLOCK | errno::EAGAIN,
}) => Ok(true),
}) => Ok(()),
Err(err) => return Err(LError::from(err).into()),
}
}