diff --git a/src/drivers/fs/virtio_fs.rs b/src/drivers/fs/virtio_fs.rs index 2cfd472a5a..fe3ba4a34e 100644 --- a/src/drivers/fs/virtio_fs.rs +++ b/src/drivers/fs/virtio_fs.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::rc::Rc; use alloc::string::{String, ToString}; use alloc::vec::Vec; @@ -15,7 +16,7 @@ use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg}; use crate::drivers::virtio::virtqueue::error::VirtqError; use crate::drivers::virtio::virtqueue::split::SplitVq; -use crate::drivers::virtio::virtqueue::{AsSliceU8, BuffSpec, Bytes, Virtq, VqIndex, VqSize}; +use crate::drivers::virtio::virtqueue::{AsSliceU8, BufferType, Virtq, VqIndex, VqSize}; use crate::fs::fuse::{self, FuseInterface}; /// A wrapper struct for the raw configuration structure. @@ -143,21 +144,19 @@ impl VirtioFsDriver { impl FuseInterface for VirtioFsDriver { fn send_command( &mut self, - cmd: &fuse::Cmd, + cmd: (Box>, Option>), rsp: &mut fuse::Rsp, ) -> Result<(), VirtqError> { - let send = ( - cmd.as_slice_u8(), - BuffSpec::Single(Bytes::new(cmd.len()).ok_or(VirtqError::BufferToLarge)?), - ); - let rsp_len = rsp.len(); - let recv = ( - rsp.as_slice_u8_mut(), - BuffSpec::Single(Bytes::new(rsp_len).ok_or(VirtqError::BufferToLarge)?), - ); + let (cmd_header, cmd_payload_opt) = cmd; + let send: &[&[u8]] = if let Some(cmd_payload) = cmd_payload_opt.as_deref() { + &[cmd_header.as_slice_u8(), cmd_payload] + } else { + &[cmd_header.as_slice_u8()] + }; + let recv = &[rsp.as_slice_u8_mut()]; let transfer_tkn = self.vqueues[1] .clone() - .prep_transfer_from_raw(Some(send), Some(recv)) + .prep_transfer_from_raw(send, recv, BufferType::Direct) .unwrap(); transfer_tkn.dispatch_blocking()?; Ok(()) diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index 70fd3f2a2a..d5837a354e 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -247,8 +247,9 @@ pub trait Virtq: VirtqPrivate { /// part via the recv argument. fn prep_transfer_from_raw( self: Rc, - send: Option<(&[u8], BuffSpec<'_>)>, - recv: Option<(&mut [u8], BuffSpec<'_>)>, + send: &[&[u8]], + recv: &[&mut [u8]], + buffer_type: BufferType, ) -> Result; /// The implementation of the method requires constraints that are incompatible with a trait object. @@ -256,559 +257,128 @@ pub trait Virtq: VirtqPrivate { /// of [Self::prep_buffer] inside the implementor. fn prep_transfer_from_raw_static( self: Rc, - send: Option<(&[u8], BuffSpec<'_>)>, - recv: Option<(&mut [u8], BuffSpec<'_>)>, + send: &[&[u8]], + recv: &[&mut [u8]], + buffer_type: BufferType, ) -> Result where Self: Sized + 'static, { - match (send, recv) { - (None, None) => Err(VirtqError::BufferNotSpecified), - (Some((send_data, send_spec)), None) => { - match send_spec { - BuffSpec::Single(size) => { - // Buffer must have the right size - if send_data.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let desc = match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) - { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - desc_lst.push( - self.mem_pool().pull_from_raw_untracked( - Rc::clone(&self.mem_pool()), - next_slice, - ), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; + if send.is_empty() && recv.is_empty() { + return Err(VirtqError::BufferNotSpecified); + } - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } + let total_send_len = send.iter().map(|slice| slice.len()).sum(); + let total_recv_len = recv.iter().map(|slice| slice.len()).sum(); + + let send_buff; + let recv_buff; + match buffer_type { + BufferType::Direct => { + let send_desc_lst = send + .iter() + .map(|slice| self.mem_pool().pull_from_raw(slice)) + .collect::, VirtqError>>()?; + send_buff = if !send.is_empty() { + Some(Buffer::Multiple { + desc_lst: send_desc_lst.into_boxed_slice(), + len: total_send_len, + next_write: 0, + }) + } else { + None + }; + + let recv_desc_lst: Vec<_> = recv + .iter() + .map(|slice| self.mem_pool().pull_from_raw(slice)) + .collect::, VirtqError>>()?; + recv_buff = if !recv.is_empty() { + Some(Buffer::Multiple { + desc_lst: recv_desc_lst.into_boxed_slice(), + len: total_recv_len, + next_write: 0, + }) + } else { + None } } - (None, Some((recv_data, recv_spec))) => { - match recv_spec { - BuffSpec::Single(size) => { - // Buffer must have the right size - if recv_data.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let desc = match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) + BufferType::Indirect => { + let send_desc_lst: Vec<_> = send + .iter() + .map(|slice| self.mem_pool().pull_from_raw_untracked(slice)) + .collect(); + let recv_desc_lst: Vec<_> = recv + .iter() + .map(|slice| self.mem_pool().pull_from_raw_untracked(slice)) + .collect(); + + let ctrl_desc = self.create_indirect_ctrl( + if !send.is_empty() { + Some(&send_desc_lst) + } else { + None + }, + if !recv.is_empty() { + Some(&recv_desc_lst) + } else { + None + }, + )?; + + let mut send_ctrl_desc = None; + let mut recv_ctrl_desc = None; + match (!send.is_empty(), !recv.is_empty()) { + (true, false) => { + send_ctrl_desc = Some(ctrl_desc); } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) - { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) + (false, true) => { + recv_ctrl_desc = Some(ctrl_desc); } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - desc_lst.push( - self.mem_pool().pull_from_raw_untracked( - Rc::clone(&self.mem_pool()), - next_slice, - ), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) + // Both send and recv have content + (true, true) => { + send_ctrl_desc = Some(ctrl_desc.no_dealloc_clone()); + recv_ctrl_desc = Some(ctrl_desc); } + // We checked at the beginning of the function. + (false, false) => unreachable!(), } - } - (Some((send_data, send_spec)), Some((recv_data, recv_spec))) => { - match (send_spec, recv_spec) { - (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - // Buffer must have the right size - if send_data.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let send_desc = match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - // Buffer must have the right size - if recv_data.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let recv_desc = match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - // Buffer must have the right size - if send_data.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let send_desc = match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) - { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) - { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) - { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) - { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - // Buffer must have the right size - if recv_data.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let recv_desc = match self - .mem_pool() - .pull_from_raw(Rc::clone(&self.mem_pool()), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - send_desc_lst.push( - self.mem_pool().pull_from_raw_untracked( - Rc::clone(&self.mem_pool()), - next_slice, - ), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - recv_desc_lst.push( - self.mem_pool().pull_from_raw_untracked( - Rc::clone(&self.mem_pool()), - next_slice, - ), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self - .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - buff_tkn: Some(BufferToken { - recv_buff: Some(Buffer::Indirect { - desc_lst: recv_desc_lst.into_boxed_slice(), - ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_data.len(), - next_write: 0, - }), - send_buff: Some(Buffer::Indirect { - desc_lst: send_desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Indirect(_), BuffSpec::Single(_)) - | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), - (BuffSpec::Single(_), BuffSpec::Indirect(_)) - | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), - } + send_buff = if !send.is_empty() { + Some(Buffer::Indirect { + desc_lst: send_desc_lst.into_boxed_slice(), + ctrl_desc: send_ctrl_desc.unwrap(), + len: total_send_len, + next_write: 0, + }) + } else { + None + }; + + recv_buff = if !recv.is_empty() { + Some(Buffer::Indirect { + desc_lst: recv_desc_lst.into_boxed_slice(), + ctrl_desc: recv_ctrl_desc.unwrap(), + len: total_recv_len, + next_write: 0, + }) + } else { + None + }; } - } + }; + + Ok(TransferToken { + buff_tkn: Some(BufferToken { + recv_buff, + send_buff, + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) } /// Provides the calley with empty buffers as specified via the `send` and `recv` function parameters, (see [BuffSpec]), in form of @@ -875,33 +445,31 @@ pub trait Virtq: VirtqPrivate { // Send buffer specified, No recv buffer (Some(spec), None) => { match spec { - BuffSpec::Single(size) => { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), size) { - Ok(desc) => { - let buffer = Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: size.into(), - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - Err(vq_err) => Err(vq_err), + BuffSpec::Single(size) => match self.mem_pool().pull(size) { + Ok(desc) => { + let buffer = Buffer::Single { + desc_lst: vec![desc].into_boxed_slice(), + len: size.into(), + next_write: 0, + }; + + Ok(BufferToken { + send_buff: Some(buffer), + recv_buff: None, + vq: self.clone(), + ret_send: true, + ret_recv: false, + reusable: true, + }) } - } + Err(vq_err) => Err(vq_err), + }, BuffSpec::Multiple(size_lst) => { let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut len = 0usize; for size in size_lst { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + match self.mem_pool().pull(*size) { Ok(desc) => desc_lst.push(desc), Err(vq_err) => return Err(vq_err), } @@ -930,10 +498,7 @@ pub trait Virtq: VirtqPrivate { for size in size_lst { // As the indirect list does only consume one descriptor for the // control descriptor, the actual list is untracked - desc_lst.push( - self.mem_pool() - .pull_untracked(Rc::clone(&self.mem_pool()), *size), - ); + desc_lst.push(self.mem_pool().pull_untracked(*size)); len += usize::from(*size); } @@ -963,33 +528,31 @@ pub trait Virtq: VirtqPrivate { // No send buffer, recv buffer is specified (None, Some(spec)) => { match spec { - BuffSpec::Single(size) => { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), size) { - Ok(desc) => { - let buffer = Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: size.into(), - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - Err(vq_err) => Err(vq_err), + BuffSpec::Single(size) => match self.mem_pool().pull(size) { + Ok(desc) => { + let buffer = Buffer::Single { + desc_lst: vec![desc].into_boxed_slice(), + len: size.into(), + next_write: 0, + }; + + Ok(BufferToken { + send_buff: None, + recv_buff: Some(buffer), + vq: self.clone(), + ret_send: false, + ret_recv: true, + reusable: true, + }) } - } + Err(vq_err) => Err(vq_err), + }, BuffSpec::Multiple(size_lst) => { let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut len = 0usize; for size in size_lst { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + match self.mem_pool().pull(*size) { Ok(desc) => desc_lst.push(desc), Err(vq_err) => return Err(vq_err), } @@ -1018,10 +581,7 @@ pub trait Virtq: VirtqPrivate { for size in size_lst { // As the indirect list does only consume one descriptor for the // control descriptor, the actual list is untracked - desc_lst.push( - self.mem_pool() - .pull_untracked(Rc::clone(&self.mem_pool()), *size), - ); + desc_lst.push(self.mem_pool().pull_untracked(*size)); len += usize::from(*size); } @@ -1052,25 +612,23 @@ pub trait Virtq: VirtqPrivate { (Some(send_spec), Some(recv_spec)) => { match (send_spec, recv_spec) { (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - let send_buff = - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), send_size) { - Ok(send_desc) => Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; + let send_buff = match self.mem_pool().pull(send_size) { + Ok(send_desc) => Some(Buffer::Single { + desc_lst: vec![send_desc].into_boxed_slice(), + len: send_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; - let recv_buff = - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), recv_size) { - Ok(recv_desc) => Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; + let recv_buff = match self.mem_pool().pull(recv_size) { + Ok(recv_desc) => Some(Buffer::Single { + desc_lst: vec![recv_desc].into_boxed_slice(), + len: recv_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; Ok(BufferToken { send_buff, @@ -1082,22 +640,21 @@ pub trait Virtq: VirtqPrivate { }) } (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - let send_buff = - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), send_size) { - Ok(send_desc) => Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; + let send_buff = match self.mem_pool().pull(send_size) { + Ok(send_desc) => Some(Buffer::Single { + desc_lst: vec![send_desc].into_boxed_slice(), + len: send_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut recv_len = 0usize; for size in recv_size_lst { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + match self.mem_pool().pull(*size) { Ok(desc) => recv_desc_lst.push(desc), Err(vq_err) => return Err(vq_err), } @@ -1124,7 +681,7 @@ pub trait Virtq: VirtqPrivate { Vec::with_capacity(send_size_lst.len()); let mut send_len = 0usize; for size in send_size_lst { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + match self.mem_pool().pull(*size) { Ok(desc) => send_desc_lst.push(desc), Err(vq_err) => return Err(vq_err), } @@ -1142,7 +699,7 @@ pub trait Virtq: VirtqPrivate { let mut recv_len = 0usize; for size in recv_size_lst { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + match self.mem_pool().pull(*size) { Ok(desc) => recv_desc_lst.push(desc), Err(vq_err) => return Err(vq_err), } @@ -1170,7 +727,7 @@ pub trait Virtq: VirtqPrivate { let mut send_len = 0usize; for size in send_size_lst { - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + match self.mem_pool().pull(*size) { Ok(desc) => send_desc_lst.push(desc), Err(vq_err) => return Err(vq_err), } @@ -1183,15 +740,14 @@ pub trait Virtq: VirtqPrivate { next_write: 0, }); - let recv_buff = - match self.mem_pool().pull(Rc::clone(&self.mem_pool()), recv_size) { - Ok(recv_desc) => Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; + let recv_buff = match self.mem_pool().pull(recv_size) { + Ok(recv_desc) => Some(Buffer::Single { + desc_lst: vec![recv_desc].into_boxed_slice(), + len: recv_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; Ok(BufferToken { send_buff, @@ -1210,10 +766,7 @@ pub trait Virtq: VirtqPrivate { for size in send_size_lst { // As the indirect list does only consume one descriptor for the // control descriptor, the actual list is untracked - send_desc_lst.push( - self.mem_pool() - .pull_untracked(Rc::clone(&self.mem_pool()), *size), - ); + send_desc_lst.push(self.mem_pool().pull_untracked(*size)); send_len += usize::from(*size); } @@ -1224,10 +777,7 @@ pub trait Virtq: VirtqPrivate { for size in recv_size_lst { // As the indirect list does only consume one descriptor for the // control descriptor, the actual list is untracked - recv_desc_lst.push( - self.mem_pool() - .pull_untracked(Rc::clone(&self.mem_pool()), *size), - ); + recv_desc_lst.push(self.mem_pool().pull_untracked(*size)); recv_len += usize::from(*size); } @@ -2267,6 +1817,11 @@ impl BufferToken { } } +pub enum BufferType { + Direct, + Indirect, +} + /// Describes the type of a buffer and unifies them. enum Buffer { /// A buffer consisting of a single [Memory Descriptor](MemDescr). @@ -2714,7 +2269,7 @@ impl MemPool { /// /// * The descriptor will consume one element of the pool. /// * The referred to memory area will NOT be deallocated upon drop. - fn pull_from_raw(&self, rc_self: Rc, slice: &[u8]) -> Result { + fn pull_from_raw(self: Rc, slice: &[u8]) -> Result { // Zero sized descriptors are NOT allowed // This also prohibids a panic due to accessing wrong index below assert!(!slice.is_empty()); @@ -2739,7 +2294,7 @@ impl MemPool { _mem_len: slice.len(), id: Some(desc_id), dealloc: Dealloc::Not, - pool: rc_self, + pool: self.clone(), }) } @@ -2756,7 +2311,7 @@ impl MemPool { /// /// * The descriptor will consume one element of the pool. /// * The referred to memory area will NOT be deallocated upon drop. - fn pull_from_raw_untracked(&self, rc_self: Rc, slice: &[u8]) -> MemDescr { + fn pull_from_raw_untracked(self: Rc, slice: &[u8]) -> MemDescr { // Zero sized descriptors are NOT allowed // This also prohibids a panic due to accessing wrong index below assert!(!slice.is_empty()); @@ -2776,7 +2331,7 @@ impl MemPool { _mem_len: slice.len(), id: None, dealloc: Dealloc::Not, - pool: rc_self, + pool: self.clone(), } } @@ -2792,7 +2347,7 @@ impl MemPool { /// * First MemPool.pull -> MemDesc with id = 3 /// * Second MemPool.pull -> MemDesc with id = 100 /// * Third MemPool.pull -> MemDesc with id = 2, - fn pull(&self, rc_self: Rc, bytes: Bytes) -> Result { + fn pull(self: Rc, bytes: Bytes) -> Result { let id = match self.pool.borrow_mut().pop() { Some(id) => id, None => return Err(VirtqError::NoDescrAvail), @@ -2819,7 +2374,7 @@ impl MemPool { _mem_len, id: Some(id), dealloc: Dealloc::AsPage, - pool: rc_self, + pool: self.clone(), }) } @@ -2832,7 +2387,7 @@ impl MemPool { /// * First MemPool.pull -> MemDesc with id = 3 /// * Second MemPool.pull -> MemDesc with id = 100 /// * Third MemPool.pull -> MemDesc with id = 2, - fn pull_untracked(&self, rc_self: Rc, bytes: Bytes) -> MemDescr { + fn pull_untracked(self: Rc, bytes: Bytes) -> MemDescr { let len = bytes.0; // Allocate heap memory via a vec, leak and cast @@ -2854,7 +2409,7 @@ impl MemPool { _mem_len, id: None, dealloc: Dealloc::AsPage, - pool: rc_self, + pool: self.clone(), } } } diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index ae52c879f3..4273f60e88 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -18,8 +18,8 @@ use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::{ - BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, TransferToken, Virtq, - VirtqPrivate, VqIndex, VqSize, + BuffSpec, Buffer, BufferToken, BufferType, Bytes, DescrFlags, MemDescr, MemPool, TransferToken, + Virtq, VirtqPrivate, VqIndex, VqSize, }; use crate::arch::mm::paging::{BasePageSize, PageSize}; use crate::arch::mm::{paging, VirtAddr}; @@ -1166,10 +1166,11 @@ impl Virtq for PackedVq { fn prep_transfer_from_raw( self: Rc, - send: Option<(&[u8], BuffSpec<'_>)>, - recv: Option<(&mut [u8], BuffSpec<'_>)>, + send: &[&[u8]], + recv: &[&mut [u8]], + buffer_type: BufferType, ) -> Result { - self.prep_transfer_from_raw_static(send, recv) + self.prep_transfer_from_raw_static(send, recv, buffer_type) } fn prep_buffer( @@ -1208,7 +1209,7 @@ impl VirtqPrivate for PackedVq { None => return Err(VirtqError::BufferToLarge), }; - let ctrl_desc = match self.mem_pool.pull(Rc::clone(&self.mem_pool), sz_indrct_lst) { + let ctrl_desc = match self.mem_pool.clone().pull(sz_indrct_lst) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), }; diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index 3eb49be836..e121fb596f 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -20,7 +20,7 @@ use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::{ - BuffSpec, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, TransferToken, Virtq, + BuffSpec, BufferToken, BufferType, Bytes, DescrFlags, MemDescr, MemPool, TransferToken, Virtq, VirtqPrivate, VqIndex, VqSize, }; use crate::arch::memory_barrier; @@ -521,10 +521,11 @@ impl Virtq for SplitVq { fn prep_transfer_from_raw( self: Rc, - send: Option<(&[u8], BuffSpec<'_>)>, - recv: Option<(&mut [u8], BuffSpec<'_>)>, + send: &[&[u8]], + recv: &[&mut [u8]], + buffer_type: BufferType, ) -> Result { - self.prep_transfer_from_raw_static(send, recv) + self.prep_transfer_from_raw_static(send, recv, buffer_type) } fn prep_buffer( @@ -559,7 +560,7 @@ impl VirtqPrivate for SplitVq { None => return Err(VirtqError::BufferToLarge), }; - let ctrl_desc = match self.mem_pool.pull(Rc::clone(&self.mem_pool), sz_indrct_lst) { + let ctrl_desc = match self.mem_pool.clone().pull(sz_indrct_lst) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), }; diff --git a/src/fd/mod.rs b/src/fd/mod.rs index a501d3ae83..5e366d0c1c 100644 --- a/src/fd/mod.rs +++ b/src/fd/mod.rs @@ -135,6 +135,8 @@ bitflags! { const S_IWOTH = 0o002; const S_IXOTH = 0o001; const S_IRWXO = 0o007; + // Allow bits unknown to us to be set externally. See bitflags documentation for further explanation. + const _ = !0; } } diff --git a/src/fs/fuse.rs b/src/fs/fuse.rs index 88eecdad3f..3d4bcaa930 100644 --- a/src/fs/fuse.rs +++ b/src/fs/fuse.rs @@ -1,10 +1,10 @@ use alloc::alloc::{alloc, Layout}; use alloc::borrow::ToOwned; use alloc::boxed::Box; +use alloc::ffi::CString; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; -use core::ffi::CStr; use core::future; use core::mem::MaybeUninit; use core::sync::atomic::{AtomicU64, Ordering}; @@ -44,7 +44,7 @@ const S_IFMT: u32 = 61440; pub(crate) trait FuseInterface { fn send_command( &mut self, - cmd: &Cmd, + cmd: (Box>, Option>), rsp: &mut Rsp, ) -> Result<(), VirtqError>; @@ -52,11 +52,12 @@ pub(crate) trait FuseInterface { } pub(crate) mod ops { + #![allow(clippy::type_complexity)] use alloc::boxed::Box; - use core::ffi::CStr; + use alloc::ffi::CString; use core::mem::MaybeUninit; - use super::{Cmd, Rsp}; + use super::{CmdHeader, Rsp}; use crate::fd::PollEvent; use crate::fs::{fuse_abi, SeekWhence}; @@ -81,8 +82,8 @@ pub(crate) mod ops { } impl Init { - pub(crate) fn create() -> (Box>, Box>) { - let cmd = Cmd::::new( + pub(crate) fn create() -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new( fuse_abi::ROOT_ID, fuse_abi::InitIn { major: 7, @@ -93,7 +94,7 @@ pub(crate) mod ops { ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -103,7 +104,7 @@ pub(crate) mod ops { impl Op for Create { const OP_CODE: fuse_abi::Opcode = fuse_abi::Opcode::Create; type InStruct = fuse_abi::CreateIn; - type InPayload = CStr; + type InPayload = CString; type OutStruct = fuse_abi::CreateOut; type OutPayload = (); } @@ -111,22 +112,23 @@ pub(crate) mod ops { impl Create { #[allow(clippy::self_named_constructors)] pub(crate) fn create( - path: &str, + path: CString, flags: u32, mode: u32, - ) -> (Box>, Box>) { - let cmd = Cmd::::from_str( + ) -> ((Box>, Option>), Box>) { + let path_bytes = path.into_bytes_with_nul().into_boxed_slice(); + let cmd = CmdHeader::::with_payload_size( fuse_abi::ROOT_ID, fuse_abi::CreateIn { flags, mode, ..Default::default() }, - path, + path_bytes.len(), ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, Some(path_bytes)), rsp) } } @@ -142,8 +144,11 @@ pub(crate) mod ops { } impl Open { - pub(crate) fn create(nid: u64, flags: u32) -> (Box>, Box>) { - let cmd = Cmd::::new( + pub(crate) fn create( + nid: u64, + flags: u32, + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new( nid, fuse_abi::OpenIn { flags, @@ -152,7 +157,7 @@ pub(crate) mod ops { ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -171,10 +176,10 @@ pub(crate) mod ops { pub(crate) fn create( nid: u64, fh: u64, - buf: &[u8], + buf: Box<[u8]>, offset: u64, - ) -> (Box>, Box>) { - let cmd = Cmd::::from_array( + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::with_payload_size( nid, fuse_abi::WriteIn { fh, @@ -182,11 +187,11 @@ pub(crate) mod ops { size: buf.len().try_into().unwrap(), ..Default::default() }, - buf, + buf.len(), ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, Some(buf)), rsp) } } @@ -210,8 +215,8 @@ pub(crate) mod ops { fh: u64, size: u32, offset: u64, - ) -> (Box>, Box>) { - let cmd = Cmd::::new( + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new( nid, fuse_abi::ReadIn { fh, @@ -222,7 +227,7 @@ pub(crate) mod ops { ); let rsp = unsafe { Rsp::::new_uninit(size.try_into().unwrap()) }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -243,8 +248,8 @@ pub(crate) mod ops { fh: u64, offset: isize, whence: SeekWhence, - ) -> (Box>, Box>) { - let cmd = Cmd::::new( + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new( nid, fuse_abi::LseekIn { fh, @@ -255,7 +260,7 @@ pub(crate) mod ops { ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -274,11 +279,14 @@ pub(crate) mod ops { } impl Readlink { - pub(crate) fn create(nid: u64, size: u32) -> (Box>, Box>) { - let cmd = Cmd::::new(nid, fuse_abi::ReadlinkIn {}); + pub(crate) fn create( + nid: u64, + size: u32, + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new(nid, fuse_abi::ReadlinkIn {}); let rsp = unsafe { Rsp::::new_uninit(size.try_into().unwrap()) }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -294,8 +302,11 @@ pub(crate) mod ops { } impl Release { - pub(crate) fn create(nid: u64, fh: u64) -> (Box>, Box>) { - let cmd = Cmd::::new( + pub(crate) fn create( + nid: u64, + fh: u64, + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new( nid, fuse_abi::ReleaseIn { fh, @@ -304,7 +315,7 @@ pub(crate) mod ops { ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -325,8 +336,8 @@ pub(crate) mod ops { fh: u64, kh: u64, event: PollEvent, - ) -> (Box>, Box>) { - let cmd = Cmd::::new( + ) -> ((Box>, Option>), Box>) { + let cmd = CmdHeader::::new( nid, fuse_abi::PollIn { fh, @@ -337,7 +348,7 @@ pub(crate) mod ops { ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, None), rsp) } } @@ -347,24 +358,28 @@ pub(crate) mod ops { impl Op for Mkdir { const OP_CODE: fuse_abi::Opcode = fuse_abi::Opcode::Mkdir; type InStruct = fuse_abi::MkdirIn; - type InPayload = CStr; + type InPayload = CString; type OutStruct = fuse_abi::EntryOut; type OutPayload = (); } impl Mkdir { - pub(crate) fn create(path: &str, mode: u32) -> (Box>, Box>) { - let cmd = Cmd::::from_str( + pub(crate) fn create( + path: CString, + mode: u32, + ) -> ((Box>, Option>), Box>) { + let path_bytes = path.into_bytes_with_nul().into_boxed_slice(); + let cmd = CmdHeader::::with_payload_size( fuse_abi::ROOT_ID, fuse_abi::MkdirIn { mode, ..Default::default() }, - path, + path_bytes.len(), ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, Some(path_bytes)), rsp) } } @@ -374,17 +389,24 @@ pub(crate) mod ops { impl Op for Unlink { const OP_CODE: fuse_abi::Opcode = fuse_abi::Opcode::Unlink; type InStruct = fuse_abi::UnlinkIn; - type InPayload = CStr; + type InPayload = CString; type OutStruct = fuse_abi::UnlinkOut; type OutPayload = (); } impl Unlink { - pub(crate) fn create(name: &str) -> (Box>, Box>) { - let cmd = Cmd::::from_str(fuse_abi::ROOT_ID, fuse_abi::UnlinkIn {}, name); + pub(crate) fn create( + name: CString, + ) -> ((Box>, Option>), Box>) { + let name_bytes = name.into_bytes_with_nul().into_boxed_slice(); + let cmd = CmdHeader::::with_payload_size( + fuse_abi::ROOT_ID, + fuse_abi::UnlinkIn {}, + name_bytes.len(), + ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, Some(name_bytes)), rsp) } } @@ -394,17 +416,24 @@ pub(crate) mod ops { impl Op for Rmdir { const OP_CODE: fuse_abi::Opcode = fuse_abi::Opcode::Rmdir; type InStruct = fuse_abi::RmdirIn; - type InPayload = CStr; + type InPayload = CString; type OutStruct = fuse_abi::RmdirOut; type OutPayload = (); } impl Rmdir { - pub(crate) fn create(name: &str) -> (Box>, Box>) { - let cmd = Cmd::::from_str(fuse_abi::ROOT_ID, fuse_abi::RmdirIn {}, name); + pub(crate) fn create( + name: CString, + ) -> ((Box>, Option>), Box>) { + let name_bytes = name.into_bytes_with_nul().into_boxed_slice(); + let cmd = CmdHeader::::with_payload_size( + fuse_abi::ROOT_ID, + fuse_abi::RmdirIn {}, + name_bytes.len(), + ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, Some(name_bytes)), rsp) } } @@ -414,17 +443,24 @@ pub(crate) mod ops { impl Op for Lookup { const OP_CODE: fuse_abi::Opcode = fuse_abi::Opcode::Lookup; type InStruct = fuse_abi::LookupIn; - type InPayload = CStr; + type InPayload = CString; type OutStruct = fuse_abi::EntryOut; type OutPayload = (); } impl Lookup { - pub(crate) fn create(name: &str) -> (Box>, Box>) { - let cmd = Cmd::::from_str(fuse_abi::ROOT_ID, fuse_abi::LookupIn {}, name); + pub(crate) fn create( + name: CString, + ) -> ((Box>, Option>), Box>) { + let name_bytes = name.into_bytes_with_nul().into_boxed_slice(); + let cmd = CmdHeader::::with_payload_size( + fuse_abi::ROOT_ID, + fuse_abi::LookupIn {}, + name_bytes.len(), + ); let rsp = unsafe { Box::new_uninit().assume_init() }; - (cmd, rsp) + ((cmd, Some(name_bytes)), rsp) } } } @@ -460,122 +496,41 @@ impl From for FileAttr { #[repr(C)] #[derive(Debug)] -pub(crate) struct Cmd { - in_header: fuse_abi::InHeader, +pub(crate) struct CmdHeader { + pub in_header: fuse_abi::InHeader, op_header: O::InStruct, - payload: O::InPayload, -} - -#[repr(C)] -#[derive(Debug)] -pub(crate) struct UninitCmd { - in_header: MaybeUninit, - op_header: MaybeUninit, - payload: [MaybeUninit], } -// We use this struct to obtain the layout of the type without the payload. -#[repr(C)] -#[derive(Debug)] -pub(crate) struct PayloadlessCmd { - in_header: MaybeUninit, - op_header: MaybeUninit, - payload: (), -} - -impl Cmd +impl CmdHeader where O: ops::Op, { fn new(nodeid: u64, op_header: O::InStruct) -> Box { - Box::new(Cmd { + Self::with_payload_size(nodeid, op_header, 0) + } +} + +impl CmdHeader { + fn with_payload_size(nodeid: u64, op_header: O::InStruct, len: usize) -> Box> { + Box::new(CmdHeader { in_header: fuse_abi::InHeader { // The length we need the provide in the header is not the same as the size of the struct because of padding, so we need to calculate it manually. len: (core::mem::size_of::() - + core::mem::size_of::()) as u32, + + core::mem::size_of::() + + len) + .try_into() + .expect("The command is too large"), opcode: O::OP_CODE as u32, nodeid, unique: 1, ..Default::default() }, op_header, - payload: (), }) } } -impl Cmd { - fn with_capacity(nodeid: u64, op_header: O::InStruct, len: usize) -> Box> { - let mut cmd = unsafe { Self::new_uninit(len) }; - cmd.in_header = MaybeUninit::new(fuse_abi::InHeader { - // The length we need the provide in the header is not the same as the size of the struct because of padding, so we need to calculate it manually. - len: (core::mem::size_of::() - + core::mem::size_of::() - + len) - .try_into() - .expect("The command is too large"), - opcode: O::OP_CODE as u32, - nodeid, - unique: 1, - ..Default::default() - }); - cmd.op_header = MaybeUninit::new(op_header); - cmd - } -} - -impl Cmd -where - O: ops::Op, -{ - fn from_array(nodeid: u64, op_header: O::InStruct, data: &[u8]) -> Box> { - let mut cmd = Self::with_capacity(nodeid, op_header, data.len()); - for (target, source) in cmd.payload.iter_mut().zip(data) { - *target = MaybeUninit::new(*source); - } - unsafe { core::intrinsics::transmute(cmd) } - } -} - -impl Cmd -where - O: ops::Op, -{ - fn from_str(nodeid: u64, op_header: O::InStruct, str: &str) -> Box> { - let str_bytes = str.as_bytes(); - // Plus one for the NUL terminator - let mut cmd = Self::with_capacity(nodeid, op_header, str_bytes.len() + 1); - for (target, source) in cmd.payload[..str_bytes.len()].iter_mut().zip(str_bytes) { - *target = MaybeUninit::new(*source); - } - cmd.payload[str_bytes.len()] = MaybeUninit::new(b'\0'); - unsafe { core::intrinsics::transmute(cmd) } - } -} - -impl AsSliceU8 for Cmd { - fn len(&self) -> usize { - self.in_header.len.try_into().unwrap() - } -} - -impl Cmd { - // MaybeUninit does not accept DSTs as type parameter - unsafe fn new_uninit(len: usize) -> Box> { - unsafe { - Box::from_raw(core::ptr::slice_from_raw_parts_mut( - alloc( - Layout::new::>() - .extend(Layout::array::(len).expect("The length is too much.")) - .expect("The layout size overflowed.") - .0 // We don't need the offset of `data_header` inside the type (the second element of the tuple) - .pad_to_align(), - ), - len, - ) as *mut UninitCmd) - } - } -} +impl AsSliceU8 for CmdHeader {} #[repr(C)] #[derive(Debug)] @@ -616,12 +571,12 @@ where } } -fn lookup(name: &str) -> Option { +fn lookup(name: CString) -> Option { let (cmd, mut rsp) = ops::Lookup::create(name); get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) + .send_command(cmd, rsp.as_mut()) .ok()?; if unsafe { rsp.out_header.assume_init_ref().error } == 0 { Some(unsafe { rsp.op_header.assume_init_ref().nodeid }) @@ -636,7 +591,7 @@ fn readlink(nid: u64) -> Result { get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let len: usize = if unsafe { rsp.out_header.assume_init_ref().len } as usize - ::core::mem::size_of::() - ::core::mem::size_of::() @@ -681,7 +636,7 @@ impl FuseFileHandleInner { get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; if unsafe { rsp.out_header.assume_init_ref().error } < 0 { Poll::Ready(Err(IoError::EIO)) @@ -721,7 +676,7 @@ impl FuseFileHandleInner { get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let len: usize = if (unsafe { rsp.out_header.assume_init_ref().len } as usize) - ::core::mem::size_of::() - ::core::mem::size_of::() @@ -748,34 +703,35 @@ impl FuseFileHandleInner { fn write(&mut self, buf: &[u8]) -> Result { debug!("FUSE write!"); - let mut len = buf.len(); - if len > MAX_WRITE_LEN { + let mut truncated_len = buf.len(); + if truncated_len > MAX_WRITE_LEN { debug!( "Writing longer than max_write_len: {} > {}", buf.len(), MAX_WRITE_LEN ); - len = MAX_WRITE_LEN; + truncated_len = MAX_WRITE_LEN; } if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) { - let (cmd, mut rsp) = ops::Write::create(nid, fh, &buf[..len], self.offset as u64); + let truncated_buf = Box::<[u8]>::from(&buf[..truncated_len]); + let (cmd, mut rsp) = ops::Write::create(nid, fh, truncated_buf, self.offset as u64); get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; if unsafe { rsp.out_header.assume_init_ref().error } < 0 { return Err(IoError::EIO); } let rsp_size = unsafe { rsp.op_header.assume_init_ref().size }; - let len: usize = if rsp_size > buf.len().try_into().unwrap() { - buf.len() + let rsp_len: usize = if rsp_size > truncated_len.try_into().unwrap() { + truncated_len } else { rsp_size.try_into().unwrap() }; - self.offset += len; - Ok(len) + self.offset += rsp_len; + Ok(rsp_len) } else { warn!("File not open, cannot read!"); Err(IoError::ENOENT) @@ -790,7 +746,7 @@ impl FuseFileHandleInner { get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; if unsafe { rsp.out_header.assume_init_ref().error } < 0 { return Err(IoError::EIO); @@ -813,7 +769,7 @@ impl Drop for FuseFileHandleInner { get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) + .send_command(cmd, rsp.as_mut()) .unwrap(); } } @@ -868,27 +824,27 @@ impl FuseDirectoryHandle { #[async_trait] impl ObjectInterface for FuseDirectoryHandle { fn readdir(&self) -> Result, IoError> { - let path: String = if let Some(name) = &self.name { - "/".to_string() + name + let path: CString = if let Some(name) = &self.name { + CString::new("/".to_string() + name).unwrap() } else { - "/".to_string() + CString::new("/".to_string()).unwrap() }; - debug!("FUSE opendir: {}", path); + debug!("FUSE opendir: {path:#?}"); - let fuse_nid = lookup(&path).ok_or(IoError::ENOENT)?; + let fuse_nid = lookup(path.clone()).ok_or(IoError::ENOENT)?; // Opendir // Flag 0x10000 for O_DIRECTORY might not be necessary let (mut cmd, mut rsp) = ops::Open::create(fuse_nid, 0x10000); - cmd.in_header.opcode = fuse_abi::Opcode::Opendir as u32; + cmd.0.in_header.opcode = fuse_abi::Opcode::Opendir as u32; get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let fuse_fh = unsafe { rsp.op_header.assume_init_ref().fh }; - debug!("FUSE readdir: {}", path); + debug!("FUSE readdir: {path:#?}"); // Linux seems to allocate a single page to store the dirfile let len = MAX_READ_LEN as u32; @@ -896,11 +852,11 @@ impl ObjectInterface for FuseDirectoryHandle { // read content of the directory let (mut cmd, mut rsp) = ops::Read::create(fuse_nid, fuse_fh, len, 0); - cmd.in_header.opcode = fuse_abi::Opcode::Readdir as u32; + cmd.0.in_header.opcode = fuse_abi::Opcode::Readdir as u32; get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let len: usize = if unsafe { rsp.out_header.assume_init_ref().len } as usize - ::core::mem::size_of::() @@ -945,7 +901,7 @@ impl ObjectInterface for FuseDirectoryHandle { get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; Ok(entries) } @@ -973,6 +929,19 @@ impl FuseDirectory { }, } } + + fn traversal_path(&self, components: &[&str]) -> CString { + let prefix_deref = self.prefix.as_deref(); + let components_with_prefix = prefix_deref.iter().chain(components.iter().rev()); + let path: String = components_with_prefix + .flat_map(|component| ["/", component]) + .collect(); + if path.is_empty() { + CString::new("/").unwrap() + } else { + CString::new(path).unwrap() + } + } } impl VfsNode for FuseDirectory { @@ -990,41 +959,23 @@ impl VfsNode for FuseDirectory { } fn traverse_readdir(&self, components: &mut Vec<&str>) -> Result, IoError> { - let path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; + let path = self.traversal_path(components); - debug!("FUSE opendir: {}", path); + debug!("FUSE opendir: {path:#?}"); - let fuse_nid = lookup(&path).ok_or(IoError::ENOENT)?; + let fuse_nid = lookup(path.clone()).ok_or(IoError::ENOENT)?; // Opendir // Flag 0x10000 for O_DIRECTORY might not be necessary let (mut cmd, mut rsp) = ops::Open::create(fuse_nid, 0x10000); - cmd.in_header.opcode = fuse_abi::Opcode::Opendir as u32; + cmd.0.in_header.opcode = fuse_abi::Opcode::Opendir as u32; get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let fuse_fh = unsafe { rsp.op_header.assume_init_ref().fh }; - debug!("FUSE readdir: {}", path); + debug!("FUSE readdir: {path:#?}"); // Linux seems to allocate a single page to store the dirfile let len = MAX_READ_LEN as u32; @@ -1032,11 +983,11 @@ impl VfsNode for FuseDirectory { // read content of the directory let (mut cmd, mut rsp) = ops::Read::create(fuse_nid, fuse_fh, len, 0); - cmd.in_header.opcode = fuse_abi::Opcode::Readdir as u32; + cmd.0.in_header.opcode = fuse_abi::Opcode::Readdir as u32; get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let len: usize = if unsafe { rsp.out_header.assume_init_ref().len } as usize - ::core::mem::size_of::() @@ -1081,40 +1032,22 @@ impl VfsNode for FuseDirectory { get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; Ok(entries) } fn traverse_stat(&self, components: &mut Vec<&str>) -> Result { - let path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; + let path = self.traversal_path(components); - debug!("FUSE stat: {}", path); + debug!("FUSE stat: {path:#?}"); // Is there a better way to implement this? - let (cmd, mut rsp) = ops::Lookup::create(&path); + let (cmd, mut rsp) = ops::Lookup::create(path); get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; if unsafe { rsp.out_header.assume_init_ref().error } != 0 { // TODO: Correct error handling @@ -1134,33 +1067,15 @@ impl VfsNode for FuseDirectory { } fn traverse_lstat(&self, components: &mut Vec<&str>) -> Result { - let path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; + let path = self.traversal_path(components); - debug!("FUSE lstat: {}", path); + debug!("FUSE lstat: {path:#?}"); - let (cmd, mut rsp) = ops::Lookup::create(&path); + let (cmd, mut rsp) = ops::Lookup::create(path); get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let attr = unsafe { rsp.op_header.assume_init().attr }; Ok(FileAttr::from(attr)) @@ -1172,40 +1087,23 @@ impl VfsNode for FuseDirectory { opt: OpenOption, mode: AccessPermission, ) -> Result, IoError> { - let mut path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; + let path = self.traversal_path(components); - debug!("FUSE lstat: {}", path); + debug!("FUSE lstat: {path:#?}"); - let (cmd, mut rsp) = ops::Lookup::create(&path); + let (cmd, mut rsp) = ops::Lookup::create(path.clone()); get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let attr = unsafe { FileAttr::from(rsp.op_header.assume_init().attr) }; let is_dir = attr.st_mode.contains(AccessPermission::S_IFDIR); - debug!("FUSE open: {}, {:?} {:?}", path, opt, mode); + debug!("FUSE open: {path:#?}, {opt:?} {mode:?}"); if is_dir { + let mut path = path.into_string().unwrap(); path.remove(0); Ok(Arc::new(FuseDirectoryHandle::new(Some(path)))) } else { @@ -1222,7 +1120,7 @@ impl VfsNode for FuseDirectory { // Differentiate between opening and creating new file, since fuse does not support O_CREAT on open. if !opt.contains(OpenOption::O_CREAT) { // 2.FUSE_LOOKUP(FUSE_ROOT_ID, “foo”) -> nodeid - file_guard.fuse_nid = lookup(&path); + file_guard.fuse_nid = lookup(path); if file_guard.fuse_nid.is_none() { warn!("Fuse lookup seems to have failed!"); @@ -1235,16 +1133,16 @@ impl VfsNode for FuseDirectory { get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; file_guard.fuse_fh = Some(unsafe { rsp.op_header.assume_init_ref().fh }); } else { // Create file (opens implicitly, returns results from both lookup and open calls) let (cmd, mut rsp) = - ops::Create::create(&path, opt.bits().try_into().unwrap(), mode.bits()); + ops::Create::create(path, opt.bits().try_into().unwrap(), mode.bits()); get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; let inner = unsafe { rsp.op_header.assume_init() }; file_guard.fuse_nid = Some(inner.entry.nodeid); @@ -1258,62 +1156,26 @@ impl VfsNode for FuseDirectory { } fn traverse_unlink(&self, components: &mut Vec<&str>) -> core::result::Result<(), IoError> { - let path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; + let path = self.traversal_path(components); - let (cmd, mut rsp) = ops::Unlink::create(&path); + let (cmd, mut rsp) = ops::Unlink::create(path); get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; trace!("unlink answer {:?}", rsp); Ok(()) } fn traverse_rmdir(&self, components: &mut Vec<&str>) -> core::result::Result<(), IoError> { - let path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; + let path = self.traversal_path(components); - let (cmd, mut rsp) = ops::Rmdir::create(&path); + let (cmd, mut rsp) = ops::Rmdir::create(path); get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; trace!("rmdir answer {:?}", rsp); Ok(()) @@ -1324,31 +1186,13 @@ impl VfsNode for FuseDirectory { components: &mut Vec<&str>, mode: AccessPermission, ) -> Result<(), IoError> { - let path: String = if components.is_empty() { - if let Some(prefix) = &self.prefix { - "/".to_string() + prefix - } else { - "/".to_string() - } - } else { - let path: String = components - .iter() - .rev() - .map(|v| "/".to_owned() + v) - .collect(); - - if let Some(prefix) = &self.prefix { - "/".to_owned() + &prefix.to_owned() + &path - } else { - path - } - }; - let (cmd, mut rsp) = ops::Mkdir::create(&path, mode.bits()); + let path = self.traversal_path(components); + let (cmd, mut rsp) = ops::Mkdir::create(path, mode.bits()); get_filesystem_driver() .ok_or(IoError::ENOSYS)? .lock() - .send_command(cmd.as_ref(), rsp.as_mut())?; + .send_command(cmd, rsp.as_mut())?; if unsafe { rsp.out_header.assume_init_ref().error } == 0 { Ok(()) } else { @@ -1365,23 +1209,20 @@ pub(crate) fn init() { if let Some(driver) = get_filesystem_driver() { let (cmd, mut rsp) = ops::Init::create(); - driver - .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) - .unwrap(); + driver.lock().send_command(cmd, rsp.as_mut()).unwrap(); trace!("fuse init answer: {:?}", rsp); let mount_point = driver.lock().get_mount_point().to_string(); if mount_point == "/" { - let fuse_nid = lookup("/").unwrap(); + let fuse_nid = lookup(c"/".to_owned()).unwrap(); // Opendir // Flag 0x10000 for O_DIRECTORY might not be necessary let (mut cmd, mut rsp) = ops::Open::create(fuse_nid, 0x10000); - cmd.in_header.opcode = fuse_abi::Opcode::Opendir as u32; + cmd.0.in_header.opcode = fuse_abi::Opcode::Opendir as u32; get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) + .send_command(cmd, rsp.as_mut()) .unwrap(); let fuse_fh = unsafe { rsp.op_header.assume_init_ref().fh }; @@ -1391,11 +1232,11 @@ pub(crate) fn init() { // read content of the directory let (mut cmd, mut rsp) = ops::Read::create(fuse_nid, fuse_fh, len, 0); - cmd.in_header.opcode = fuse_abi::Opcode::Readdir as u32; + cmd.0.in_header.opcode = fuse_abi::Opcode::Readdir as u32; get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) + .send_command(cmd, rsp.as_mut()) .unwrap(); let len: usize = if unsafe { rsp.out_header.assume_init_ref().len } as usize @@ -1438,7 +1279,7 @@ pub(crate) fn init() { get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) + .send_command(cmd, rsp.as_mut()) .unwrap(); // remove predefined directories @@ -1449,11 +1290,12 @@ pub(crate) fn init() { warn!("Fuse don't mount the host directories 'tmp' and 'proc' into the guest file system!"); for i in entries { - let (cmd, mut rsp) = ops::Lookup::create(&i); + let i_cstr = CString::new(i.clone()).unwrap(); + let (cmd, mut rsp) = ops::Lookup::create(i_cstr); get_filesystem_driver() .unwrap() .lock() - .send_command(cmd.as_ref(), rsp.as_mut()) + .send_command(cmd, rsp.as_mut()) .unwrap(); let attr = unsafe { rsp.op_header.assume_init().attr };