From 1c02eebc71a0ede4e75fea516920697850bbe030 Mon Sep 17 00:00:00 2001 From: Alejandro Soto Date: Tue, 4 Jan 2022 03:51:32 -0600 Subject: Implement unmount --- src/fuse/mount.rs | 37 +++++++++++++++++++++------------- src/fuse/session.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/util.rs | 10 +++++++++- 3 files changed, 84 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/fuse/mount.rs b/src/fuse/mount.rs index 9b03961..c924a9a 100644 --- a/src/fuse/mount.rs +++ b/src/fuse/mount.rs @@ -6,6 +6,7 @@ use std::{ io::{AsRawFd, RawFd}, net::UnixStream, }, + path::{Path, PathBuf}, process::Command, }; @@ -97,7 +98,7 @@ impl> Extend for Options { pub fn mount_sync(mountpoint: M, options: &Options) -> Result where - M: AsRef, + M: AsRef + Into, { let (left_side, right_side) = UnixStream::pair()?; @@ -112,24 +113,18 @@ where ) .unwrap(); - let mut command = Command::new("fusermount3"); + let mut command = Command::new(FUSERMOUNT_CMD); if !options.0.is_empty() { - command.args(&[ - OsStr::new("-o"), - &options.0, - OsStr::new("--"), - mountpoint.as_ref(), - ]); - } else { - command.arg(mountpoint); - }; + command.args(&[OsStr::new("-o"), &options.0]); + } + command.args(&[OsStr::new("--"), mountpoint.as_ref().as_ref()]); let mut fusermount = command.env("_FUSE_COMMFD", right_fd.to_string()).spawn()?; // recvmsg() should fail if fusermount exits (last open fd is closed) drop(right_side); - let session_fd = (|| { + let session_fd = { let mut buffer = cmsg_space!(RawFd); let message = recvmsg( left_side.as_raw_fd(), @@ -145,10 +140,10 @@ where }; session_fd.ok_or(MountError::Fusermount) - })(); + }; match session_fd { - Ok(session_fd) => Ok(Start::new(DumbFd(session_fd))), + Ok(session_fd) => Ok(Start::new(DumbFd(session_fd), mountpoint.into())), Err(error) => { drop(left_side); @@ -157,3 +152,17 @@ where } } } + +pub(crate) fn unmount_sync>(mountpoint: M) -> Result<(), MountError> { + let status = Command::new(FUSERMOUNT_CMD) + .args(&[OsStr::new("-zuq"), OsStr::new("--"), mountpoint.as_ref()]) + .status()?; + + if status.success() { + Ok(()) + } else { + Err(MountError::Fusermount) + } +} + +const FUSERMOUNT_CMD: &str = "fusermount3"; diff --git a/src/fuse/session.rs b/src/fuse/session.rs index d7b6501..55fedcb 100644 --- a/src/fuse/session.rs +++ b/src/fuse/session.rs @@ -4,6 +4,7 @@ use std::{ marker::PhantomData, ops::ControlFlow, os::unix::io::{IntoRawFd, RawFd}, + path::PathBuf, sync::{Arc, Mutex}, }; @@ -22,6 +23,7 @@ use bytemuck::bytes_of; use smallvec::SmallVec; use crate::{ + mount::{unmount_sync, MountError}, proto::{self, InHeader, Structured}, util::{page_size, DumbFd, OutputChain}, Errno, FuseError, FuseResult, @@ -34,6 +36,7 @@ use super::{ pub struct Start { session_fd: DumbFd, + mountpoint: PathBuf, } pub struct Session { @@ -42,6 +45,7 @@ pub struct Session { buffers: Mutex>, buffer_semaphore: Arc, buffer_pages: usize, + mountpoint: Mutex>, } pub struct Endpoint<'a> { @@ -93,6 +97,15 @@ impl Session { } } + pub fn unmount_sync(&self) -> Result<(), MountError> { + let mountpoint = self.mountpoint.lock().unwrap().take(); + if let Some(mountpoint) = &mountpoint { + unmount_sync(mountpoint)?; + } + + Ok(()) + } + pub(crate) fn ok(&self, unique: u64, output: OutputChain<'_>) -> FuseResult<()> { self.send(unique, 0, output) } @@ -212,6 +225,24 @@ impl Session { } } +impl Drop for Start { + fn drop(&mut self) { + if !self.mountpoint.as_os_str().is_empty() { + let _ = unmount_sync(&self.mountpoint); + } + } +} + +impl Drop for Session { + fn drop(&mut self) { + if let Some(mountpoint) = self.mountpoint.get_mut().unwrap().take() { + let _ = unmount_sync(&mountpoint); + } + + drop(DumbFd(*self.session_fd.get_ref())); // Close + } +} + impl<'o> Dispatch<'o> { pub fn op(self) -> Op<'o> { use Dispatch::*; @@ -253,7 +284,11 @@ impl Endpoint<'_> { let mut readable = tokio::select! { readable = session_fd.readable() => readable?, - _ = session_fd.writable() => return Ok(ControlFlow::Break(())), + + _ = session_fd.writable() => { + self.session.mountpoint.lock().unwrap().take(); + return Ok(ControlFlow::Break(())); + } }; let mut read = |fd: &AsyncFd| read(*fd.get_ref(), buffer); @@ -264,6 +299,7 @@ impl Endpoint<'_> { match result { // Interrupted + //TODO: libfuse docs say that this has some side effects Err(error) if error.kind() == std::io::ErrorKind::NotFound => continue, result => break result, @@ -330,11 +366,12 @@ impl Endpoint<'_> { } impl Start { - pub async fn start(self, mut init: F) -> FuseResult> + pub async fn start(mut self, mut init: F) -> FuseResult> where F: FnOnce(Op<'_, ops::Init>) -> Done<'_>, { - let session_fd = self.session_fd.into_raw_fd(); + let mountpoint = std::mem::take(&mut self.mountpoint); + let session_fd = self.session_fd.take().into_raw_fd(); let flags = OFlag::O_NONBLOCK | OFlag::O_LARGEFILE; fcntl(session_fd, FcntlArg::F_SETFL(flags)).unwrap(); @@ -353,6 +390,7 @@ impl Start { buffers: Mutex::new(buffers), buffer_semaphore: Arc::new(Semaphore::new(buffer_count)), buffer_pages, + mountpoint: Mutex::new(Some(mountpoint)), }; let mut init_buffer = session.buffers.get_mut().unwrap().pop().unwrap(); @@ -368,8 +406,17 @@ impl Start { } } - pub(crate) fn new(session_fd: DumbFd) -> Self { - Start { session_fd } + pub fn unmount_sync(mut self) -> Result<(), MountError> { + // This prevents Start::drop() from unmounting a second time + let mountpoint = std::mem::take(&mut self.mountpoint); + unmount_sync(&mountpoint) + } + + pub(crate) fn new(session_fd: DumbFd, mountpoint: PathBuf) -> Self { + Start { + session_fd, + mountpoint, + } } } diff --git a/src/util.rs b/src/util.rs index c21442f..5da19c8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -29,6 +29,12 @@ pub struct OutputChain<'a> { pub struct OutputChainIter<'a>(Option<&'a OutputChain<'a>>); +impl DumbFd { + pub fn take(&mut self) -> DumbFd { + DumbFd(std::mem::replace(&mut self.0, -1)) + } +} + impl IntoRawFd for DumbFd { fn into_raw_fd(self) -> RawFd { let fd = self.0; @@ -39,7 +45,9 @@ impl IntoRawFd for DumbFd { impl Drop for DumbFd { fn drop(&mut self) { - let _ = close(self.0); + if !self.0.is_negative() { + let _ = close(self.0); + } } } -- cgit v1.2.3