diff --git a/src/abi/fuse_abi_linux.rs b/src/abi/fuse_abi_linux.rs index e5751d658..b67848b6d 100644 --- a/src/abi/fuse_abi_linux.rs +++ b/src/abi/fuse_abi_linux.rs @@ -197,6 +197,11 @@ const INIT_EXT: u64 = 0x4000_0000; // This flag indicates whether the guest kernel enable per-file dax const PERFILE_DAX: u64 = 0x2_0000_0000; +// This flag indicates whether to enable fd-passthrough. It was defined in the +// Anolis kernel but not in the upstream kernel. To avoid collision, we'll set +// it to the most significant bit. +const FD_PASSTHROUGH: u64 = 0x8000_0000_0000_0000; + /** * * fuse_attr flags @@ -442,6 +447,9 @@ bitflags! { /// -. write has WRITE_KILL_PRIV const HANDLE_KILLPRIV_V2 = HANDLE_KILLPRIV_V2; + /// Indicates the kernel support fuse fd passthrough. + const FD_PASSTHROUGH = FD_PASSTHROUGH; + /// The fuse_init_in is extended. const INIT_EXT = INIT_EXT; @@ -912,7 +920,7 @@ unsafe impl ByteValued for CreateIn {} pub struct OpenOut { pub fh: u64, pub open_flags: u32, - pub padding: u32, + pub passthrough: u32, } unsafe impl ByteValued for OpenOut {} diff --git a/src/abi/fuse_abi_macos.rs b/src/abi/fuse_abi_macos.rs index 55b14e998..fd6d43e27 100644 --- a/src/abi/fuse_abi_macos.rs +++ b/src/abi/fuse_abi_macos.rs @@ -683,7 +683,7 @@ unsafe impl ByteValued for CreateIn {} pub struct OpenOut { pub fh: u64, pub open_flags: u32, - pub padding: u32, + pub passthrough: u32, } unsafe impl ByteValued for OpenOut {} diff --git a/src/api/filesystem/sync_io.rs b/src/api/filesystem/sync_io.rs index 35f3fda48..c3b7df43c 100644 --- a/src/api/filesystem/sync_io.rs +++ b/src/api/filesystem/sync_io.rs @@ -313,9 +313,9 @@ pub trait FileSystem { inode: Self::Inode, flags: u32, fuse_flags: u32, - ) -> io::Result<(Option, OpenOptions)> { + ) -> io::Result<(Option, OpenOptions, Option)> { // Matches the behavior of libfuse. - Ok((None, OpenOptions::empty())) + Ok((None, OpenOptions::empty(), None)) } /// Create and open a file. @@ -332,13 +332,14 @@ pub trait FileSystem { /// addition to the optional `Handle` and the `OpenOptions`, the file system must also return an /// `Entry` for the file. This increases the lookup count for the `Inode` associated with the /// file by 1. + #[allow(clippy::type_complexity)] fn create( &self, ctx: &Context, parent: Self::Inode, name: &CStr, args: CreateIn, - ) -> io::Result<(Entry, Option, OpenOptions)> { + ) -> io::Result<(Entry, Option, OpenOptions, Option)> { Err(io::Error::from_raw_os_error(libc::ENOSYS)) } @@ -1021,7 +1022,7 @@ impl FileSystem for Arc { inode: Self::Inode, flags: u32, fuse_flags: u32, - ) -> io::Result<(Option, OpenOptions)> { + ) -> io::Result<(Option, OpenOptions, Option)> { self.deref().open(ctx, inode, flags, fuse_flags) } @@ -1031,7 +1032,7 @@ impl FileSystem for Arc { parent: Self::Inode, name: &CStr, args: CreateIn, - ) -> io::Result<(Entry, Option, OpenOptions)> { + ) -> io::Result<(Entry, Option, OpenOptions, Option)> { self.deref().create(ctx, parent, name, args) } diff --git a/src/api/server/sync_io.rs b/src/api/server/sync_io.rs index 66b70bc87..ba2606fca 100644 --- a/src/api/server/sync_io.rs +++ b/src/api/server/sync_io.rs @@ -390,11 +390,11 @@ impl Server { let OpenIn { flags, fuse_flags } = ctx.r.read_obj().map_err(Error::DecodeMessage)?; match self.fs.open(ctx.context(), ctx.nodeid(), flags, fuse_flags) { - Ok((handle, opts)) => { + Ok((handle, opts, passthrough)) => { let out = OpenOut { fh: handle.map(Into::into).unwrap_or(0), open_flags: opts.bits(), - ..Default::default() + passthrough: passthrough.unwrap_or_default(), }; ctx.reply_ok(Some(out), None) @@ -973,7 +973,7 @@ impl Server { })?; match self.fs.create(ctx.context(), ctx.nodeid(), name, args) { - Ok((entry, handle, opts)) => { + Ok((entry, handle, opts, passthrough)) => { let entry_out = EntryOut { nodeid: entry.inode, generation: entry.generation, @@ -983,10 +983,11 @@ impl Server { attr_valid_nsec: entry.attr_timeout.subsec_nanos(), attr: entry.attr.into(), }; + let open_out = OpenOut { fh: handle.map(Into::into).unwrap_or(0), open_flags: opts.bits(), - ..Default::default() + passthrough: passthrough.unwrap_or_default(), }; // Kind of a hack to write both structs. diff --git a/src/api/vfs/async_io.rs b/src/api/vfs/async_io.rs index 1cf3a9ad4..2a98338aa 100644 --- a/src/api/vfs/async_io.rs +++ b/src/api/vfs/async_io.rs @@ -71,7 +71,9 @@ impl AsyncFileSystem for Vfs { Err(Error::from_raw_os_error(libc::ENOSYS)) } else { match self.get_real_rootfs(inode)? { - (Left(fs), idata) => fs.open(ctx, idata.ino(), flags, fuse_flags), + (Left(fs), idata) => fs + .open(ctx, idata.ino(), flags, fuse_flags) + .map(|(a, b, _)| (a, b)), (Right(fs), idata) => fs .async_open(ctx, idata.ino(), flags, fuse_flags) .await @@ -90,7 +92,9 @@ impl AsyncFileSystem for Vfs { validate_path_component(name)?; match self.get_real_rootfs(parent)? { - (Left(fs), idata) => fs.create(ctx, idata.ino(), name, args), + (Left(fs), idata) => fs + .create(ctx, idata.ino(), name, args) + .map(|(a, b, c, _)| (a, b, c)), (Right(fs), idata) => { fs.async_create(ctx, idata.ino(), name, args) .await diff --git a/src/api/vfs/sync_io.rs b/src/api/vfs/sync_io.rs index 8ba9831f5..3418fbe4a 100644 --- a/src/api/vfs/sync_io.rs +++ b/src/api/vfs/sync_io.rs @@ -299,7 +299,7 @@ impl FileSystem for Vfs { inode: VfsInode, flags: u32, fuse_flags: u32, - ) -> Result<(Option, OpenOptions)> { + ) -> Result<(Option, OpenOptions, Option)> { #[cfg(target_os = "linux")] if self.opts.load().no_open { return Err(Error::from_raw_os_error(libc::ENOSYS)); @@ -308,7 +308,7 @@ impl FileSystem for Vfs { (Left(fs), idata) => fs.open(ctx, idata.ino(), flags, fuse_flags), (Right(fs), idata) => fs .open(ctx, idata.ino(), flags, fuse_flags) - .map(|(h, opt)| (h.map(Into::into), opt)), + .map(|(h, opt, passthrough)| (h.map(Into::into), opt, passthrough)), } } @@ -318,16 +318,16 @@ impl FileSystem for Vfs { parent: VfsInode, name: &CStr, args: CreateIn, - ) -> Result<(Entry, Option, OpenOptions)> { + ) -> Result<(Entry, Option, OpenOptions, Option)> { validate_path_component(name)?; match self.get_real_rootfs(parent)? { (Left(fs), idata) => fs.create(ctx, idata.ino(), name, args), (Right(fs), idata) => { fs.create(ctx, idata.ino(), name, args) - .map(|(mut a, b, c)| { + .map(|(mut a, b, c, d)| { self.convert_entry(idata.fs_idx(), a.inode, &mut a)?; - Ok((a, b, c)) + Ok((a, b, c, d)) })? } } diff --git a/src/passthrough/mod.rs b/src/passthrough/mod.rs index e93dcbc12..b025bfcae 100644 --- a/src/passthrough/mod.rs +++ b/src/passthrough/mod.rs @@ -1689,7 +1689,7 @@ mod tests { umask: 0, fuse_flags: 0, }; - let (entry, handle, _) = fs.create(&ctx, ROOT_ID, &fname, args).unwrap(); + let (entry, handle, _, _) = fs.create(&ctx, ROOT_ID, &fname, args).unwrap(); let handle_data = fs.handle_map.get(handle.unwrap(), entry.inode).unwrap(); let mut f = unsafe { File::from_raw_fd(handle_data.get_handle_raw_fd()) }; let mut buf = [0; 4]; @@ -1700,7 +1700,7 @@ mod tests { // Then Open an existing file with O_WRONLY, we should be able to read it as well. let fname = CString::new("existfile").unwrap(); let entry = fs.lookup(&ctx, ROOT_ID, &fname).unwrap(); - let (handle, _) = fs + let (handle, _, _) = fs .open(&ctx, entry.inode, libc::O_WRONLY as u32, 0) .unwrap(); let handle_data = fs.handle_map.get(handle.unwrap(), entry.inode).unwrap(); diff --git a/src/passthrough/sync_io.rs b/src/passthrough/sync_io.rs index 8c6fc7238..7a5161e18 100644 --- a/src/passthrough/sync_io.rs +++ b/src/passthrough/sync_io.rs @@ -178,7 +178,7 @@ impl PassthroughFs { inode: Inode, flags: u32, fuse_flags: u32, - ) -> io::Result<(Option, OpenOptions)> { + ) -> io::Result<(Option, OpenOptions, Option)> { let killpriv = if self.killpriv_v2.load(Ordering::Relaxed) && (fuse_flags & FOPEN_IN_KILL_SUIDGID != 0) { @@ -204,7 +204,7 @@ impl PassthroughFs { _ => {} }; - Ok((Some(handle), opts)) + Ok((Some(handle), opts, None)) } fn do_getattr( @@ -396,6 +396,7 @@ impl FileSystem for PassthroughFs { Err(io::Error::from_raw_os_error(libc::ENOSYS)) } else { self.do_open(inode, flags | (libc::O_DIRECTORY as u32), 0) + .map(|(a, b, _)| (a, b)) } } @@ -516,7 +517,7 @@ impl FileSystem for PassthroughFs { inode: Inode, flags: u32, fuse_flags: u32, - ) -> io::Result<(Option, OpenOptions)> { + ) -> io::Result<(Option, OpenOptions, Option)> { if self.no_open.load(Ordering::Relaxed) { info!("fuse: open is not supported."); Err(io::Error::from_raw_os_error(libc::ENOSYS)) @@ -548,7 +549,7 @@ impl FileSystem for PassthroughFs { parent: Inode, name: &CStr, args: CreateIn, - ) -> io::Result<(Entry, Option, OpenOptions)> { + ) -> io::Result<(Entry, Option, OpenOptions, Option)> { self.validate_path_component(name)?; let dir = self.inode_map.get(parent)?; @@ -604,7 +605,7 @@ impl FileSystem for PassthroughFs { _ => {} }; - Ok((entry, ret_handle, opts)) + Ok((entry, ret_handle, opts, None)) } fn unlink(&self, _ctx: &Context, parent: Inode, name: &CStr) -> io::Result<()> {