diff options
Diffstat (limited to 'devices/src/virtio/fs/server.rs')
-rw-r--r-- | devices/src/virtio/fs/server.rs | 99 |
1 files changed, 92 insertions, 7 deletions
diff --git a/devices/src/virtio/fs/server.rs b/devices/src/virtio/fs/server.rs index 9c3136d..32b5008 100644 --- a/devices/src/virtio/fs/server.rs +++ b/devices/src/virtio/fs/server.rs @@ -12,8 +12,8 @@ use libc; use sys_util::error; use crate::virtio::fs::filesystem::{ - Context, DirEntry, Entry, FileSystem, GetxattrReply, ListxattrReply, ZeroCopyReader, - ZeroCopyWriter, + Context, DirEntry, Entry, FileSystem, GetxattrReply, IoctlReply, ListxattrReply, + ZeroCopyReader, ZeroCopyWriter, }; use crate::virtio::fs::fuse::*; use crate::virtio::fs::{Error, Result}; @@ -1097,11 +1097,35 @@ impl<F: FileSystem + Sync> Server<F> { Ok(0) } - fn ioctl(&self, in_header: InHeader, _r: Reader, w: Writer) -> Result<usize> { - if let Err(e) = self.fs.ioctl() { - reply_error(e, in_header.unique, w) - } else { - Ok(0) + fn ioctl(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> { + let IoctlIn { + fh, + flags, + cmd, + arg, + in_size, + out_size, + } = r.read_obj().map_err(Error::DecodeMessage)?; + + let res = self.fs.ioctl( + in_header.into(), + fh.into(), + IoctlFlags::from_bits_truncate(flags), + cmd, + arg, + in_size, + out_size, + r, + ); + + match res { + Ok(reply) => match reply { + IoctlReply::Retry { input, output } => { + retry_ioctl(in_header.unique, input, output, w) + } + IoctlReply::Done(res) => finish_ioctl(in_header.unique, res, w), + }, + Err(e) => reply_error(e, in_header.unique, w), } } @@ -1186,6 +1210,67 @@ impl<F: FileSystem + Sync> Server<F> { } } +fn retry_ioctl( + unique: u64, + input: Vec<IoctlIovec>, + output: Vec<IoctlIovec>, + mut w: Writer, +) -> Result<usize> { + // We don't need to check for overflow here because if adding these 2 values caused an overflow + // we would have run out of memory before reaching this point. + if input.len() + output.len() > IOCTL_MAX_IOV { + return Err(Error::TooManyIovecs(( + input.len() + output.len(), + IOCTL_MAX_IOV, + ))); + } + + let len = size_of::<OutHeader>() + + size_of::<IoctlOut>() + + (input.len() * size_of::<IoctlIovec>()) + + (output.len() * size_of::<IoctlIovec>()); + let header = OutHeader { + len: len as u32, + error: 0, + unique, + }; + let out = IoctlOut { + result: 0, + flags: IoctlFlags::RETRY.bits(), + in_iovs: input.len() as u32, + out_iovs: output.len() as u32, + }; + + w.write_obj(header).map_err(Error::EncodeMessage)?; + w.write_obj(out).map_err(Error::EncodeMessage)?; + for i in input.into_iter().chain(output.into_iter()) { + w.write_obj(i).map_err(Error::EncodeMessage)?; + } + + debug_assert_eq!(len, w.bytes_written()); + Ok(w.bytes_written()) +} + +fn finish_ioctl(unique: u64, res: io::Result<Vec<u8>>, w: Writer) -> Result<usize> { + let (out, data) = match res { + Ok(data) => { + let out = IoctlOut { + result: 0, + ..Default::default() + }; + (out, Some(data)) + } + Err(e) => { + let out = IoctlOut { + result: -e.raw_os_error().unwrap_or(libc::EIO), + ..Default::default() + }; + (out, None) + } + }; + reply_ok(Some(out), data.as_ref().map(|d| &d[..]), unique, w) +} + fn reply_ok<T: DataInit>( out: Option<T>, data: Option<&[u8]>, |