diff --git a/src/passthrough/sync_io.rs b/src/passthrough/sync_io.rs index 4fb738bc8..a404946eb 100644 --- a/src/passthrough/sync_io.rs +++ b/src/passthrough/sync_io.rs @@ -656,6 +656,21 @@ impl FileSystem for PassthroughFs { let mut f = ManuallyDrop::new(f); + #[cfg(all(target_os = "linux", feature = "fusedev"))] + match w.append_fd_buf(&f.as_raw_fd(), size as usize, Some(offset)) { + Ok(len) => { + return Ok(len); + } + Err(e) => { + let err_code = e.raw_os_error().unwrap_or(-1); + if err_code != libc::ENOSYS && err_code != libc::ENOTSUP && err_code != libc::EINVAL + { + return Err(e); + } + // fallback to write_from + } + } + w.write_from(&mut *f, size as usize, offset) } @@ -696,6 +711,21 @@ impl FileSystem for PassthroughFs { None }; + #[cfg(all(target_os = "linux", feature = "fusedev"))] + match r.splice_to(&f.as_raw_fd(), size as usize, Some(offset)) { + Ok(len) => { + return Ok(len); + } + Err(e) => { + let err_code = e.raw_os_error().unwrap_or(-1); + if err_code != libc::ENOSYS && err_code != libc::ENOTSUP && err_code != libc::EINVAL + { + return Err(e); + } + // fallback to read_to + } + } + r.read_to(&mut *f, size as usize, offset) } diff --git a/tests/example/passthroughfs.rs b/tests/example/passthroughfs.rs index 856c8a261..85fa76e29 100644 --- a/tests/example/passthroughfs.rs +++ b/tests/example/passthroughfs.rs @@ -19,12 +19,13 @@ pub struct Daemon { server: Arc>>, thread_cnt: u32, session: Option, + enable_splice: bool, } #[allow(dead_code)] impl Daemon { /// Creates a fusedev daemon instance - pub fn new(src: &str, mountpoint: &str, thread_cnt: u32) -> Result { + pub fn new(src: &str, mountpoint: &str, thread_cnt: u32, enable_splice: bool) -> Result { // create vfs let vfs = Vfs::new(VfsOptions { no_open: false, @@ -47,6 +48,7 @@ impl Daemon { server: Arc::new(Server::new(Arc::new(vfs))), thread_cnt, session: None, + enable_splice, }) } @@ -60,6 +62,7 @@ impl Daemon { let mut server = FuseServer { server: self.server.clone(), ch: se.new_channel().unwrap(), + enable_splice: self.enable_splice, }; let _thread = thread::Builder::new() .name("fuse_server".to_string()) @@ -93,12 +96,21 @@ impl Drop for Daemon { struct FuseServer { server: Arc>>, ch: FuseChannel, + enable_splice: bool, } impl FuseServer { fn svc_loop(&mut self) -> Result<()> { // Given error EBADF, it means kernel has shut down this session. let _ebadf = std::io::Error::from_raw_os_error(libc::EBADF); + if self.enable_splice { + if self.server.is_support_splice_write() { + self.ch.enable_splice_write().unwrap(); + } + if self.server.is_support_splice_read() { + self.ch.enable_splice_read().unwrap(); + } + } loop { if let Some((reader, writer)) = self .ch diff --git a/tests/smoke.rs b/tests/smoke.rs index c3261f692..bec64ab3a 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -88,11 +88,19 @@ mod fusedev_tests { let tmp_dir = TempDir::new().unwrap(); let mnt_dir = tmp_dir.as_path().to_str().unwrap(); info!( - "test passthroughfs src {:?} mountpoint {}", + "test passthroughfs src {:?} mountpoint {} splice false", src_dir, mnt_dir ); - let mut daemon = passthroughfs::Daemon::new(src_dir, mnt_dir, 2).unwrap(); + let mut daemon = passthroughfs::Daemon::new(src_dir, mnt_dir, 2, false).unwrap(); + daemon.mount().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + assert!(validate_two_git_directory(src_dir, mnt_dir)); + daemon.umount().unwrap(); + drop(daemon); + // test with splice + std::thread::sleep(std::time::Duration::from_secs(1)); + let mut daemon = passthroughfs::Daemon::new(src_dir, mnt_dir, 2, true).unwrap(); daemon.mount().unwrap(); std::thread::sleep(std::time::Duration::from_secs(1)); assert!(validate_two_git_directory(src_dir, mnt_dir));