diff --git a/src/ll/request.rs b/src/ll/request.rs index 29287151..be2f4dde 100644 --- a/src/ll/request.rs +++ b/src/ll/request.rs @@ -1317,11 +1317,6 @@ mod op { #[expect(dead_code)] header: &'a fuse_in_header, } - impl<'a> Destroy<'a> { - pub(crate) fn reply(&self) -> Response<'a> { - Response::new_empty() - } - } /// Control device #[derive(Debug)] diff --git a/src/request.rs b/src/request.rs index b3369211..06871b00 100644 --- a/src/request.rs +++ b/src/request.rs @@ -35,7 +35,7 @@ pub(crate) struct RequestWithSender<'a> { /// Channel sender for sending the reply ch: ChannelSender, /// Parsed request - request: ll::AnyRequest<'a>, + pub(crate) request: ll::AnyRequest<'a>, } impl<'a> RequestWithSender<'a> { @@ -55,7 +55,7 @@ impl<'a> RequestWithSender<'a> { /// Dispatch request to the given filesystem. /// This calls the appropriate filesystem operation method for the /// request and sends back the returned reply to the kernel - pub(crate) fn dispatch(&self, se: &mut Session) { + pub(crate) fn dispatch(&self, se: &Session) { debug!("{}", self.request); let res = match self.dispatch_req(se) { Ok(Some(resp)) => resp, @@ -67,7 +67,7 @@ impl<'a> RequestWithSender<'a> { fn dispatch_req( &self, - se: &mut Session, + se: &Session, ) -> Result>, Errno> { let op = self.request.operation().map_err(|_| Errno::ENOSYS)?; // Implement allow_root & access check for auto_unmount @@ -103,11 +103,9 @@ impl<'a> RequestWithSender<'a> { error!("Unexpected FUSE_INIT after handshake completed"); return Err(Errno::EIO); } - // Filesystem destroyed - ll::Operation::Destroy(x) => { - se.filesystem.destroy(); - se.destroyed = true; - return Ok(Some(x.reply())); + ll::Operation::Destroy(_x) => { + // This is handled before dispatch call. + return Err(Errno::EIO); } // Any operation is invalid after destroy _ if se.destroyed => { @@ -557,7 +555,7 @@ impl<'a> RequestWithSender<'a> { /// Create a reply object for this request that can be passed to the filesystem /// implementation and makes sure that a request is replied exactly once - fn reply(&self) -> T { + pub(crate) fn reply(&self) -> T { Reply::new(self.request.unique(), ReplySender::Channel(self.ch.clone())) } diff --git a/src/session.rs b/src/session.rs index 4eff2b82..32218241 100644 --- a/src/session.rs +++ b/src/session.rs @@ -32,11 +32,13 @@ use crate::Errno; use crate::Filesystem; use crate::KernelConfig; use crate::MountOption; +use crate::ReplyEmpty; use crate::Request; use crate::channel::Channel; use crate::channel::ChannelSender; use crate::dev_fuse::DevFuse; use crate::ll; +use crate::ll::Operation; use crate::ll::Response; use crate::ll::Version; use crate::ll::flags::init_flags::InitFlags; @@ -169,15 +171,43 @@ impl Session { self.handshake(buf)?; + let ret = self.event_loop(buf); + + self.filesystem.destroy(); + self.destroyed = true; + + match ret { + Err(e) => Err(e), + Ok(None) => Ok(()), + Ok(Some(destroy_reply)) => { + destroy_reply.ok(); + Ok(()) + } + } + } + + /// Return `Some` if reply to `FUSE_DESTROY` needs to be sent. + fn event_loop(&self, buf: &mut [u8]) -> io::Result> { loop { // Read the next request from the given channel to kernel driver // The kernel driver makes sure that we get exactly one request per read match self.ch.receive(buf) { Ok(size) => match RequestWithSender::new(self.ch.sender(), &buf[..size]) { // Dispatch request - Some(req) => req.dispatch(&mut self), + Some(req) => { + if let Ok(Operation::Destroy(_)) = req.request.operation() { + return Ok(Some(req.reply())); + } else { + req.dispatch(self) + } + } // Quit loop on illegal request - None => break, + None => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid request", + )); + } }, Err(err) => match err.raw_os_error() { Some( @@ -185,13 +215,12 @@ impl Session { | EINTR // Interrupted system call, retry | EAGAIN // Explicitly instructed to try again ) => continue, - Some(ENODEV) => break, + Some(ENODEV) => return Ok(None), // Unhandled error _ => return Err(err), }, } } - Ok(()) } fn handshake(&mut self, buf: &mut [u8]) -> io::Result<()> {