fuser
fuser copied to clipboard
async prototype
I am working on the async feature. I seem to have a working prototype. Here's what it looks like from the application's perspective.
#[async_trait]
impl Filesystem for FS{
async fn lookup(&self, _req: RequestMeta, parent: u64, name: &Path) -> Result<Entry, Errno> {
...
}
...
}
fn main() {
...
let mut se = fuser::Session::new(fs, mountpoint, &options)
.expect("Failed to create Session");
let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
match rt.block_on(async { se.run_with_notifications().await }) {
Ok(()) => info!("Session ended safely"),
Err(e) => info!("Session ended with error {e:?}")
}
}
@cberner is this what you wanted?
I used the ioctl example because it's small so there were fewer edits needed to make it work.
start ioctl application
[rlawrence@ye-olde-dell experiment]$ RUST_LOG=info ./target/debug/examples/ioctl /tmp/mnt
in the other terminal
[rlawrence@ye-olde-dell experiment]$ client=$PWD/target/debug/examples/ioctl_client
[rlawrence@ye-olde-dell experiment]$ cd /tmp/mnt
[rlawrence@ye-olde-dell mnt]$ $client
Initial size: 0 bytes
Set size to 4096 bytes
After set(4096), size: 4096 bytes
Set size to 0 bytes
After set(0), size: 0 bytes
ioctl_client completed successfully.
[rlawrence@ye-olde-dell mnt]$ cd ..
[rlawrence@ye-olde-dell tmp]$ fusermount3 -u /tmp/mnt/
ioctl says
[2025-08-04T17:52:03Z INFO fuser::session] Mounting /tmp/mnt
[2025-08-04T17:52:03Z INFO fuser::session] Running FUSE session in single-threaded mode
[2025-08-04T17:52:54Z INFO ioctl] Session ended with error Custom { kind: Other, error: "Poll error, revents: 0x8." }
[2025-08-04T17:52:54Z INFO fuser::session] unmounting session at /tmp/mnt
seems ok to me?
I think #[async_trait] might be unnecessary as of Rust 1.75 (link), but I'm not entirely sure.
And then rather than add an async run_with_notifications() to Session. I was thinking we'd add a struct like:
struct<T: AsyncFilesystem> AsyncToLegacyAdapter<T> {
rt: tokio::Runtime,
inner: T,
}
impl<T> Filesystem for AsyncToLegacyAdapter<T> {
// implementation of Fileystem which calls the AsyncFilesystem
// this doesn't need to be particularly efficient, as long as it is correct.
fn lookup(...) {
// delegate to the inner async filesystem, and execute it on the tokio runtime
let result = rt.block_on(self.inner.lookup(...));
...
}
}
then the user would do something like:
struct MyAsyncFS {}
impl AsyncFilesystem for MyAsyncFS {
...
}
fn main() {
...
let adapter = AsyncToLegacyAdapter::new(MyAsyncFS::new());
fuser::mount2(adapter, mountpoint, options);
}