From c821e96e2a5e78f64cda4202da3220754f6504bc Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Wed, 18 Mar 2020 13:26:18 +0100 Subject: [PATCH] vhost_user_fs: Implement support for FUSE_LSEEK Implement missing support for FUSE_LSEEK, which basically implies calling to libc::lseek on the file handle. As this operation alters the file offset, we take a write lock on the File's RwLock. Signed-off-by: Sergio Lopez --- vhost_user_fs/src/filesystem.rs | 17 ++++++++++++----- vhost_user_fs/src/passthrough.rs | 28 ++++++++++++++++++++++++++++ vhost_user_fs/src/server.rs | 23 ++++++++++++++++++----- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/vhost_user_fs/src/filesystem.rs b/vhost_user_fs/src/filesystem.rs index 4d80a9b20..c755113b9 100644 --- a/vhost_user_fs/src/filesystem.rs +++ b/vhost_user_fs/src/filesystem.rs @@ -1084,6 +1084,18 @@ pub trait FileSystem { Err(io::Error::from_raw_os_error(libc::ENOSYS)) } + /// Reposition read/write file offset. + fn lseek( + &self, + ctx: Context, + inode: Self::Inode, + handle: Self::Handle, + offset: u64, + whence: u32, + ) -> io::Result { + Err(io::Error::from_raw_os_error(libc::ENOSYS)) + } + /// TODO: support this fn getlk(&self) -> io::Result<()> { Err(io::Error::from_raw_os_error(libc::ENOSYS)) @@ -1118,9 +1130,4 @@ pub trait FileSystem { fn notify_reply(&self) -> io::Result<()> { Err(io::Error::from_raw_os_error(libc::ENOSYS)) } - - /// TODO: support this - fn lseek(&self) -> io::Result<()> { - Err(io::Error::from_raw_os_error(libc::ENOSYS)) - } } diff --git a/vhost_user_fs/src/passthrough.rs b/vhost_user_fs/src/passthrough.rs index 07217e12e..83b7e300b 100644 --- a/vhost_user_fs/src/passthrough.rs +++ b/vhost_user_fs/src/passthrough.rs @@ -1616,4 +1616,32 @@ impl FileSystem for PassthroughFs { Err(io::Error::last_os_error()) } } + + fn lseek( + &self, + _ctx: Context, + inode: Inode, + handle: Handle, + offset: u64, + whence: u32, + ) -> io::Result { + let data = self + .handles + .read() + .unwrap() + .get(&handle) + .filter(|hd| hd.inode == inode) + .map(Arc::clone) + .ok_or_else(ebadf)?; + + let fd = data.file.write().unwrap().as_raw_fd(); + + // Safe because this doesn't modify any memory and we check the return value. + let res = unsafe { libc::lseek(fd, offset as libc::off64_t, whence as libc::c_int) }; + if res < 0 { + Err(io::Error::last_os_error()) + } else { + Ok(res as u64) + } + } } diff --git a/vhost_user_fs/src/server.rs b/vhost_user_fs/src/server.rs index cb2120796..21826127d 100644 --- a/vhost_user_fs/src/server.rs +++ b/vhost_user_fs/src/server.rs @@ -1241,11 +1241,24 @@ impl Server { } } - fn lseek(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result { - if let Err(e) = self.fs.lseek() { - reply_error(e, in_header.unique, w) - } else { - Ok(0) + fn lseek(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result { + let LseekIn { + fh, offset, whence, .. + } = r.read_obj().map_err(Error::DecodeMessage)?; + + match self.fs.lseek( + Context::from(in_header), + in_header.nodeid.into(), + fh.into(), + offset, + whence, + ) { + Ok(offset) => { + let out = LseekOut { offset }; + + reply_ok(Some(out), None, in_header.unique, w) + } + Err(e) => reply_error(e, in_header.unique, w), } } }