diff options
author | Chirantan Ekbote <chirantan@chromium.org> | 2020-03-17 17:51:19 +0900 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-19 08:13:29 +0000 |
commit | a07d84ad6876197368ed23b641c2400a44809e69 (patch) | |
tree | c3de9b9cb0017315ad7777f9b198b4b05d2317d0 /devices/src | |
parent | 6d2a83482737cac0e5777a00e27d34e704eedb71 (diff) | |
download | crosvm-a07d84ad6876197368ed23b641c2400a44809e69.tar crosvm-a07d84ad6876197368ed23b641c2400a44809e69.tar.gz crosvm-a07d84ad6876197368ed23b641c2400a44809e69.tar.bz2 crosvm-a07d84ad6876197368ed23b641c2400a44809e69.tar.lz crosvm-a07d84ad6876197368ed23b641c2400a44809e69.tar.xz crosvm-a07d84ad6876197368ed23b641c2400a44809e69.tar.zst crosvm-a07d84ad6876197368ed23b641c2400a44809e69.zip |
devices: fs: Add support for fuse minor version 28
BUG=b:150264964 TEST=vm.Virtiofs Change-Id: I544329b63352956647d07aefdfce3118947d0821 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2105820 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
Diffstat (limited to 'devices/src')
-rw-r--r-- | devices/src/virtio/fs/filesystem.rs | 30 | ||||
-rw-r--r-- | devices/src/virtio/fs/fuse.rs | 43 | ||||
-rw-r--r-- | devices/src/virtio/fs/server.rs | 37 |
3 files changed, 107 insertions, 3 deletions
diff --git a/devices/src/virtio/fs/filesystem.rs b/devices/src/virtio/fs/filesystem.rs index 232ff99..eb9726c 100644 --- a/devices/src/virtio/fs/filesystem.rs +++ b/devices/src/virtio/fs/filesystem.rs @@ -1139,4 +1139,34 @@ pub trait FileSystem { fn lseek(&self) -> io::Result<()> { Err(io::Error::from_raw_os_error(libc::ENOSYS)) } + + /// Copy a range of data from one file to another + /// + /// Performs an optimized copy between two file descriptors without the additional cost of + /// transferring data through the kernel module to user space (glibc) and then back into + /// the file system again. + /// + /// In case this method is not implemented, glibc falls back to reading data from the source and + /// writing to the destination. + /// + /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent + /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `copy_file_range` + /// without forwarding them to the file system. + /// + /// All values accepted by the `copy_file_range(2)` system call are valid values for `flags` and + /// must be handled by the file system. + fn copy_file_range( + &self, + ctx: Context, + inode_src: Self::Inode, + handle_src: Self::Handle, + offset_src: u64, + inode_dst: Self::Inode, + handle_dst: Self::Handle, + offset_dst: u64, + length: u64, + flags: u64, + ) -> io::Result<usize> { + Err(io::Error::from_raw_os_error(libc::ENOSYS)) + } } diff --git a/devices/src/virtio/fs/fuse.rs b/devices/src/virtio/fs/fuse.rs index 612202b..0533a5c 100644 --- a/devices/src/virtio/fs/fuse.rs +++ b/devices/src/virtio/fs/fuse.rs @@ -12,8 +12,11 @@ use libc; /// Version number of this interface. pub const KERNEL_VERSION: u32 = 7; +/// Oldest supported minor version of the fuse interface. +pub const OLDEST_SUPPORTED_KERNEL_MINOR_VERSION: u32 = 27; + /// Minor version number of this interface. -pub const KERNEL_MINOR_VERSION: u32 = 27; +pub const KERNEL_MINOR_VERSION: u32 = 28; /// The ID of the inode corresponding to the root directory of the file system. pub const ROOT_ID: u64 = 1; @@ -56,6 +59,12 @@ const FOPEN_KEEP_CACHE: u32 = 2; /// The file is not seekable. const FOPEN_NONSEEKABLE: u32 = 4; +/// Allow caching the directory entries. +const FOPEN_CACHE_DIR: u32 = 8; + +/// This file is stream-like (i.e., no file position). +const FOPEN_STREAM: u32 = 16; + bitflags! { /// Options controlling the behavior of files opened by the server in response /// to an open or create request. @@ -63,6 +72,8 @@ bitflags! { const DIRECT_IO = FOPEN_DIRECT_IO; const KEEP_CACHE = FOPEN_KEEP_CACHE; const NONSEEKABLE = FOPEN_NONSEEKABLE; + const CACHE_DIR = FOPEN_CACHE_DIR; + const STREAM = FOPEN_STREAM; } } @@ -131,6 +142,15 @@ const HANDLE_KILLPRIV: u32 = 524288; /// FileSystem supports posix acls. const POSIX_ACL: u32 = 1048576; +/// Reading the device after an abort returns `ECONNABORTED`. +const ABORT_ERROR: u32 = 2097152; + +/// The reply to the `init` message contains the max number of request pages. +const MAX_PAGES: u32 = 4194304; + +/// Cache `readlink` responses. +const CACHE_SYMLINKS: u32 = 8388608; + bitflags! { /// A bitfield passed in as a parameter to and returned from the `init` method of the /// `FileSystem` trait. @@ -297,6 +317,9 @@ bitflags! { /// /// This feature is disabled by default. const POSIX_ACL = POSIX_ACL; + + /// Indicates that the kernel may cache responses to `readlink` calls. + const CACHE_SYMLINKS = CACHE_SYMLINKS; } } @@ -511,6 +534,7 @@ pub enum Opcode { Readdirplus = 44, Rename2 = 45, Lseek = 46, + CopyFileRange = 47, } #[repr(u32)] @@ -830,7 +854,9 @@ pub struct InitOut { pub congestion_threshold: u16, pub max_write: u32, pub time_gran: u32, - pub unused: [u32; 9], + pub max_pages: u16, + pub padding: u16, + pub unused: [u32; 8], } unsafe impl DataInit for InitOut {} @@ -1049,3 +1075,16 @@ pub struct LseekOut { pub offset: u64, } unsafe impl DataInit for LseekOut {} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct CopyFileRangeIn { + pub fh_src: u64, + pub off_src: u64, + pub nodeid_dst: u64, + pub fh_dst: u64, + pub off_dst: u64, + pub len: u64, + pub flags: u64, +} +unsafe impl DataInit for CopyFileRangeIn {} diff --git a/devices/src/virtio/fs/server.rs b/devices/src/virtio/fs/server.rs index 32b5008..76f2830 100644 --- a/devices/src/virtio/fs/server.rs +++ b/devices/src/virtio/fs/server.rs @@ -118,6 +118,7 @@ impl<F: FileSystem + Sync> Server<F> { Some(Opcode::Readdirplus) => self.readdirplus(in_header, r, w), Some(Opcode::Rename2) => self.rename2(in_header, r, w), Some(Opcode::Lseek) => self.lseek(in_header, r, w), + Some(Opcode::CopyFileRange) => self.copy_file_range(in_header, r, w), None => reply_error( io::Error::from_raw_os_error(libc::ENOSYS), in_header.unique, @@ -809,7 +810,7 @@ impl<F: FileSystem + Sync> Server<F> { return reply_ok(Some(out), None, in_header.unique, w); } - if minor < KERNEL_MINOR_VERSION { + if minor < OLDEST_SUPPORTED_KERNEL_MINOR_VERSION { error!( "Unsupported fuse protocol minor version: {}.{}", major, minor @@ -1208,6 +1209,40 @@ impl<F: FileSystem + Sync> Server<F> { Ok(0) } } + + fn copy_file_range(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> { + let CopyFileRangeIn { + fh_src, + off_src, + nodeid_dst, + fh_dst, + off_dst, + len, + flags, + } = r.read_obj().map_err(Error::DecodeMessage)?; + + match self.fs.copy_file_range( + Context::from(in_header), + in_header.nodeid.into(), + fh_src.into(), + off_src, + nodeid_dst.into(), + fh_dst.into(), + off_dst, + len, + flags, + ) { + Ok(count) => { + let out = WriteOut { + size: count as u32, + ..Default::default() + }; + + reply_ok(Some(out), None, in_header.unique, w) + } + Err(e) => reply_error(e, in_header.unique, w), + } + } } fn retry_ioctl( |