From 34c26c01cde72ce2a816d82674141d70ef9fee5c Mon Sep 17 00:00:00 2001 From: Mathias Rieder Date: Thu, 19 Mar 2026 08:09:19 +0100 Subject: [PATCH 1/2] Add support for external Tokio runtimes in TokioAdapter --- src/experimental.rs | 49 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/experimental.rs b/src/experimental.rs index 9185b08d..5a347a63 100644 --- a/src/experimental.rs +++ b/src/experimental.rs @@ -121,23 +121,54 @@ impl GetAttrResponse { } } +#[derive(Debug)] +enum Runtime { + /// Use the runtime provided by the user + External(tokio::runtime::Handle), + /// Use an internal runtime + Internal(tokio::runtime::Runtime), +} + /// Adapter to allow running an [`AsyncFilesystem`] with tokio's runtime. #[derive(Debug)] pub struct TokioAdapter { inner: Arc, - runtime: tokio::runtime::Runtime, + runtime: Runtime, } impl TokioAdapter { + + /// Create a new adapter with an internal tokio runtime. pub fn new(inner: T) -> Self { Self { inner: Arc::new(inner), - runtime: tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap(), + runtime: Runtime::Internal( + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(), + ), } } + + /// Use an existing tokio runtime. This is useful if you want to run the filesystem + /// in an existing application that already uses a tokio runtime. + pub fn with_runtime(inner: T, runtime_handle: tokio::runtime::Handle) -> Self { + Self { + inner: Arc::new(inner), + runtime: Runtime::External(runtime_handle), + } + } + + fn spawn(&self, fut: F) + where + F: std::future::Future + Send + 'static, + { + match &self.runtime { + Runtime::External(handle) => handle.spawn(fut), + Runtime::Internal(rt) => rt.spawn(fut), + }; + } } impl Filesystem for TokioAdapter { @@ -145,7 +176,7 @@ impl Filesystem for TokioAdapter let context: RequestContext = req.into(); let name = name.to_os_string(); let inner = self.inner.clone(); - self.runtime.spawn(async move { + self.spawn(async move { match inner.lookup(&context, parent, &name).await { Ok(LookupResponse { ttl, @@ -160,7 +191,7 @@ impl Filesystem for TokioAdapter fn getattr(&self, req: &Request, ino: INodeNo, fh: Option, reply: ReplyAttr) { let context: RequestContext = req.into(); let inner = self.inner.clone(); - self.runtime.spawn(async move { + self.spawn(async move { match inner.getattr(&context, ino, fh).await { Ok(GetAttrResponse { ttl, attr }) => reply.attr(&ttl, &attr), Err(e) => reply.error(e), @@ -181,7 +212,7 @@ impl Filesystem for TokioAdapter ) { let context: RequestContext = req.into(); let inner = self.inner.clone(); - self.runtime.spawn(async move { + self.spawn(async move { let mut buf = vec![]; match inner .read(&context, ino, fh, offset, size, flags, lock_owner, &mut buf) @@ -203,7 +234,7 @@ impl Filesystem for TokioAdapter ) { let context: RequestContext = req.into(); let inner = self.inner.clone(); - self.runtime.spawn(async move { + self.spawn(async move { let builder = DirEntListBuilder { entries: &mut reply, }; From 7c2aca280d868d7714dbeaeddc8c4ee5565196ae Mon Sep 17 00:00:00 2001 From: Mathias Rieder Date: Thu, 19 Mar 2026 15:53:59 +0100 Subject: [PATCH 2/2] wip --- src/experimental.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/experimental.rs b/src/experimental.rs index 5a347a63..ad0e2b70 100644 --- a/src/experimental.rs +++ b/src/experimental.rs @@ -244,7 +244,43 @@ impl Filesystem for TokioAdapter } }); } -} + + fn flush( + &self, + _req: &Request, + _ino: INodeNo, + _fh: FileHandle, + _lock_owner: LockOwner, + reply: crate::ReplyEmpty, + ) { + reply.error(Errno::ENOSYS); + } + + fn ioctl( + &self, + req: &Request, + ino: INodeNo, + fh: FileHandle, + flags: crate::IoctlFlags, + cmd: u32, + in_data: &[u8], + out_size: u32, + reply: crate::ReplyIoctl, + + ) { + reply.error(Errno::ENOSYS); + } + + fn getxattr(&self, _req: &Request, ino: INodeNo, name: &OsStr, size: u32, reply: crate::ReplyXattr) { + reply.error(Errno::ENOSYS); + } + + fn listxattr(&self, _req: &Request, ino: INodeNo, size: u32, reply: crate::ReplyXattr) { + reply.error(Errno::ENOSYS); + } + + } + /// Experimental async API. Expect this to change in the future #[async_trait::async_trait]