Skip to content

Commit a51ee32

Browse files
committed
fusedev: stop an async worker on a read error it can't retry
The async server logged a read error it didn't know and read again. Now that a tokio task waits for the device to become readable, a device that stays readable but fails every read made the task spin at full CPU and log on every pass. EINVAL for a buffer smaller than the kernel's requests does that. Retry ENOENT, which the kernel returns when a request was interrupted before the read, and stop the task on any other error. The synchronous server does the same. Signed-off-by: Ilan Joselevich <personal@ilanjoselevich.com>
1 parent 92dc2e7 commit a51ee32

2 files changed

Lines changed: 11 additions & 9 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
through the IO driver of the tokio runtime that polls it, and checks its state flag every 100ms
6060
while idle. Polling it on a tokio runtime without IO enabled panics. `fuse-backend-fusedev`
6161
needs tokio 1.53.3.
62+
- The async fusedev server retries a read that fails with `ENOENT` and stops the task on read
63+
errors it doesn't know, like the synchronous server. It used to log them and read again.
6264
- [254](https://github.com/cloud-hypervisor/fuse-backend-rs/pull/254): `fuse-backend-rs` is now a thin facade re-exporting the sub-crates. Every
6365
historical `fuse_backend_rs::{abi, api, buffer, common, transport, passthrough,
6466
overlayfs}` import path and cargo feature name (`fusedev`, `virtiofs`,

‎crates/fuse-backend-fusedev/src/linux_session.rs‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,8 +1334,10 @@ mod asyncio {
13341334
// The fuse device was unmounted or the connection was aborted.
13351335
break 'serve;
13361336
}
1337-
Some(libc::EINTR) => {
1338-
// Interrupted by a signal, retry the read.
1337+
Some(libc::EINTR) | Some(libc::ENOENT) => {
1338+
// Interrupted by a signal, or the kernel dropped
1339+
// the request because it was interrupted. Retry
1340+
// the read.
13391341
continue 'serve;
13401342
}
13411343
Some(libc::EAGAIN) => {
@@ -1353,17 +1355,15 @@ mod asyncio {
13531355
tokio::task::yield_now().await;
13541356
continue 'serve;
13551357
}
1356-
None => {
1358+
_ => {
13571359
// The error isn't an OS error, for example because the
1358-
// runtime is shutting down. Waiting again would fail the
1359-
// same way.
1360+
// runtime is shutting down, or one that retrying won't
1361+
// fix, such as EINVAL for a buffer smaller than the
1362+
// kernel's requests. Retrying would spin on it, so stop
1363+
// like the synchronous server does.
13601364
error!("failed to read request from fuse device fd, {}", e);
13611365
break 'serve;
13621366
}
1363-
_ => {
1364-
// TODO: error handling
1365-
error!("failed to read request from fuse device fd, {}", e);
1366-
}
13671367
}
13681368
}
13691369
}

0 commit comments

Comments
 (0)