Skip to content

Commit 3ffc7cd

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 2c5f8fb commit 3ffc7cd

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
@@ -44,6 +44,8 @@
4444
through the IO driver of the tokio runtime that polls it, and checks its state flag every 100ms
4545
while idle. Polling it on a tokio runtime without IO enabled panics. `fuse-backend-fusedev`
4646
needs tokio 1.53.3.
47+
- The async fusedev server retries a read that fails with `ENOENT` and stops the task on read
48+
errors it doesn't know, like the synchronous server. It used to log them and read again.
4749
- [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
4850
historical `fuse_backend_rs::{abi, api, buffer, common, transport, passthrough,
4951
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
@@ -1257,8 +1257,10 @@ mod asyncio {
12571257
// The fuse device was unmounted or the connection was aborted.
12581258
break 'serve;
12591259
}
1260-
Some(libc::EINTR) => {
1261-
// Interrupted by a signal, retry the read.
1260+
Some(libc::EINTR) | Some(libc::ENOENT) => {
1261+
// Interrupted by a signal, or the kernel dropped
1262+
// the request because it was interrupted. Retry
1263+
// the read.
12621264
continue 'serve;
12631265
}
12641266
Some(libc::EAGAIN) => {
@@ -1276,17 +1278,15 @@ mod asyncio {
12761278
tokio::task::yield_now().await;
12771279
continue 'serve;
12781280
}
1279-
None => {
1281+
_ => {
12801282
// The error isn't an OS error, for example because the
1281-
// runtime is shutting down. Waiting again would fail the
1282-
// same way.
1283+
// runtime is shutting down, or one that retrying won't
1284+
// fix, such as EINVAL for a buffer smaller than the
1285+
// kernel's requests. Retrying would spin on it, so stop
1286+
// like the synchronous server does.
12831287
error!("failed to read request from fuse device fd, {}", e);
12841288
break 'serve;
12851289
}
1286-
_ => {
1287-
// TODO: error handling
1288-
error!("failed to read request from fuse device fd, {}", e);
1289-
}
12901290
}
12911291
}
12921292
}

0 commit comments

Comments
 (0)