From 07cc73bddc28ef0a9dfbef9c894b0d41fed34c48 Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Thu, 12 Mar 2020 15:22:06 +0100 Subject: [PATCH] vhost_user_fs: add a flag to disable extended attributes Extended attributes (xattr) support has a huge impact on write performance. The reason for this is that, if enabled, FUSE sends a setxattr request after each write operation, and due to the inode locking inside the kernel during said request, the ability to execute the operations in parallel becomes heavily limited. Signed-off-by: Sergio Lopez --- src/bin/vhost_user_fs.rs | 7 +++++++ vhost_user_fs/src/passthrough.rs | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/bin/vhost_user_fs.rs b/src/bin/vhost_user_fs.rs index 15f7b8987..b738de182 100644 --- a/src/bin/vhost_user_fs.rs +++ b/src/bin/vhost_user_fs.rs @@ -289,6 +289,11 @@ fn main() { .takes_value(true) .min_values(1), ) + .arg( + Arg::with_name("disable-xattr") + .long("disable-xattr") + .help("Disable support for extended attributes"), + ) .get_matches(); // Retrieve arguments @@ -302,12 +307,14 @@ fn main() { Some(size) => size.parse().expect("Invalid argument for thread-pool-size"), None => THREAD_POOL_SIZE, }; + let xattr: bool = !cmd_arguments.is_present("disable-xattr"); // Convert into appropriate types let sock = String::from(sock); let fs_cfg = passthrough::Config { root_dir: shared_dir.to_string(), + xattr, ..Default::default() }; let fs = PassthroughFs::new(fs_cfg).unwrap(); diff --git a/vhost_user_fs/src/passthrough.rs b/vhost_user_fs/src/passthrough.rs index d2c48179f..07217e12e 100644 --- a/vhost_user_fs/src/passthrough.rs +++ b/vhost_user_fs/src/passthrough.rs @@ -231,6 +231,13 @@ pub struct Config { /// /// The default is `/`. pub root_dir: String, + + /// Whether the file system should support Extended Attributes (xattr). Enabling this feature may + /// have a significant impact on performance, especially on write parallelism. This is the result + /// of FUSE attempting to remove the special file privileges after each write request. + /// + /// The default value for this options is `false`. + pub xattr: bool, } impl Default for Config { @@ -241,6 +248,7 @@ impl Default for Config { cache_policy: Default::default(), writeback: false, root_dir: String::from("/"), + xattr: false, } } } @@ -1461,6 +1469,10 @@ impl FileSystem for PassthroughFs { value: &[u8], flags: u32, ) -> io::Result<()> { + if !self.cfg.xattr { + return Err(io::Error::from_raw_os_error(libc::ENOSYS)); + } + // The f{set,get,remove,list}xattr functions don't work on an fd opened with `O_PATH` so we // need to get a new fd. let file = self.open_inode(inode, libc::O_RDONLY | libc::O_NONBLOCK)?; @@ -1489,6 +1501,10 @@ impl FileSystem for PassthroughFs { name: &CStr, size: u32, ) -> io::Result { + if !self.cfg.xattr { + return Err(io::Error::from_raw_os_error(libc::ENOSYS)); + } + // The f{set,get,remove,list}xattr functions don't work on an fd opened with `O_PATH` so we // need to get a new fd. let file = self.open_inode(inode, libc::O_RDONLY | libc::O_NONBLOCK)?; @@ -1517,6 +1533,10 @@ impl FileSystem for PassthroughFs { } fn listxattr(&self, _ctx: Context, inode: Inode, size: u32) -> io::Result { + if !self.cfg.xattr { + return Err(io::Error::from_raw_os_error(libc::ENOSYS)); + } + // The f{set,get,remove,list}xattr functions don't work on an fd opened with `O_PATH` so we // need to get a new fd. let file = self.open_inode(inode, libc::O_RDONLY | libc::O_NONBLOCK)?; @@ -1544,6 +1564,10 @@ impl FileSystem for PassthroughFs { } fn removexattr(&self, _ctx: Context, inode: Inode, name: &CStr) -> io::Result<()> { + if !self.cfg.xattr { + return Err(io::Error::from_raw_os_error(libc::ENOSYS)); + } + // The f{set,get,remove,list}xattr functions don't work on an fd opened with `O_PATH` so we // need to get a new fd. let file = self.open_inode(inode, libc::O_RDONLY | libc::O_NONBLOCK)?;