From 49dcd4ad780c5073dac1b5270b7181ad13e568f7 Mon Sep 17 00:00:00 2001 From: zjregee Date: Thu, 13 Jun 2024 16:42:00 +0800 Subject: [PATCH 1/3] add virtiofs integrations --- integrations/virtiofs/.gitignore | 1 + integrations/virtiofs/Cargo.toml | 39 ++++ integrations/virtiofs/src/error.rs | 83 +++++++ integrations/virtiofs/src/lib.rs | 20 ++ integrations/virtiofs/src/virtiofs.rs | 240 ++++++++++++++++++++ integrations/virtiofs/src/virtiofs_util.rs | 249 +++++++++++++++++++++ 6 files changed, 632 insertions(+) create mode 100644 integrations/virtiofs/.gitignore create mode 100644 integrations/virtiofs/Cargo.toml create mode 100644 integrations/virtiofs/src/error.rs create mode 100644 integrations/virtiofs/src/lib.rs create mode 100644 integrations/virtiofs/src/virtiofs.rs create mode 100644 integrations/virtiofs/src/virtiofs_util.rs diff --git a/integrations/virtiofs/.gitignore b/integrations/virtiofs/.gitignore new file mode 100644 index 000000000000..03314f77b5aa --- /dev/null +++ b/integrations/virtiofs/.gitignore @@ -0,0 +1 @@ +Cargo.lock diff --git a/integrations/virtiofs/Cargo.toml b/integrations/virtiofs/Cargo.toml new file mode 100644 index 000000000000..b91ddcf1385f --- /dev/null +++ b/integrations/virtiofs/Cargo.toml @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +[package] +description = "virtiofs integration for Apache OpenDAL" +name = "virtiofs_opendal" + +authors = ["Apache OpenDAL "] +edition = "2021" +homepage = "https://opendal.apache.org/" +license = "Apache-2.0" +repository = "https://github.com/apache/opendal" +rust-version = "1.75" +version = "0.1.0" + +[dependencies] +snafu = "0.8.3" +libc = "0.2.139" +vhost = "0.11.0" +virtio-queue = "0.11.0" +vmm-sys-util = "0.12.1" +virtio-bindings = "0.2.1" +vhost-user-backend = "0.14.0" +anyhow = { version = "1.0.86", features = ["std"] } +vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic"] } diff --git a/integrations/virtiofs/src/error.rs b/integrations/virtiofs/src/error.rs new file mode 100644 index 000000000000..d8c0ff125c88 --- /dev/null +++ b/integrations/virtiofs/src/error.rs @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::io; + +use anyhow::Error as AnyError; +use snafu::prelude::Snafu; + +/// Error is a error struct returned by all ovfs functions. +#[derive(Debug, Snafu)] +#[non_exhaustive] +pub enum Error { + #[snafu(display("Vhost user fs error: {}, source: {:?}", message, source))] + VhostUserFsError { + message: String, + #[snafu(source(false))] + source: Option, + }, + #[snafu(display("Unexpected error: {}, source: {:?}", message, source))] + Unexpected { + message: String, + #[snafu(source(false))] + source: Option, + }, +} + +impl From for io::Error { + fn from(error: Error) -> io::Error { + match error { + Error::VhostUserFsError { message, source } => { + let message = format!("Vhost user fs error: {}", message); + match source { + Some(source) => io::Error::new( + io::ErrorKind::Other, + format!("{}, source: {:?}", message, source), + ), + None => io::Error::new(io::ErrorKind::Other, message), + } + } + Error::Unexpected { message, source } => { + let message = format!("Unexpected error: {}", message); + match source { + Some(source) => io::Error::new( + io::ErrorKind::Other, + format!("{}, source: {:?}", message, source), + ), + None => io::Error::new(io::ErrorKind::Other, message), + } + } + } + } +} + +/// Result is a result wrapper in ovfs. +pub type Result = std::result::Result; + +pub fn new_vhost_user_fs_error(message: &str, source: Option) -> Error { + Error::VhostUserFsError { + message: message.to_string(), + source, + } +} + +pub fn new_unexpected_error(message: &str, source: Option) -> Error { + Error::Unexpected { + message: message.to_string(), + source, + } +} diff --git a/integrations/virtiofs/src/lib.rs b/integrations/virtiofs/src/lib.rs new file mode 100644 index 000000000000..e9e65c3b0de6 --- /dev/null +++ b/integrations/virtiofs/src/lib.rs @@ -0,0 +1,20 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +mod error; +mod virtiofs; +mod virtiofs_util; diff --git a/integrations/virtiofs/src/virtiofs.rs b/integrations/virtiofs/src/virtiofs.rs new file mode 100644 index 000000000000..a7e33e22751d --- /dev/null +++ b/integrations/virtiofs/src/virtiofs.rs @@ -0,0 +1,240 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::io; +use std::sync::RwLock; + +use vhost::vhost_user::message::VhostUserProtocolFeatures; +use vhost::vhost_user::message::VhostUserVirtioFeatures; +use vhost::vhost_user::Backend; +use vhost_user_backend::VhostUserBackend; +use vhost_user_backend::VringMutex; +use vhost_user_backend::VringState; +use vhost_user_backend::VringT; +use virtio_bindings::bindings::virtio_config::VIRTIO_F_VERSION_1; +use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; +use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_INDIRECT_DESC; +use vm_memory::ByteValued; +use vm_memory::GuestMemoryAtomic; +use vm_memory::GuestMemoryMmap; +use vm_memory::Le32; +use vmm_sys_util::epoll::EventSet; +use vmm_sys_util::eventfd::EventFd; + +use crate::error::*; + +/// Marks an event from the high priority queue. +const HIPRIO_QUEUE_EVENT: u16 = 0; +/// Marks an event from the request queue. +const REQ_QUEUE_EVENT: u16 = 1; +/// The maximum number of bytes in VirtioFsConfig tag field. +const MAX_TAG_LEN: usize = 36; +/// The maximum queue size supported. +const QUEUE_SIZE: usize = 32768; +/// The number of request queues supported. +/// The vitrofs spec allows for multiple request queues, but we'll only support one. +const REQUEST_QUEUES: usize = 1; +/// In addition to request queues there is one high priority queue. +const NUM_QUEUES: usize = REQUEST_QUEUES + 1; + +/// VhostUserFsThread represents the actual worker process used to handle file system requests from VMs. +struct VhostUserFsThread { + mem: Option>, + vu_req: Option, + event_idx: bool, + kill_event_fd: EventFd, +} + +impl VhostUserFsThread { + fn new() -> Result { + let event_fd = EventFd::new(libc::EFD_NONBLOCK).map_err(|err| { + new_unexpected_error("failed to create kill eventfd", Some(err.into())) + })?; + Ok(VhostUserFsThread { + mem: None, + vu_req: None, + event_idx: false, + kill_event_fd: event_fd, + }) + } + + /// Process filesystem requests one at a time in a serialized manner. + fn handle_event_serial(&self, device_event: u16, vrings: &[VringMutex]) -> Result<()> { + let mut vring_state = match device_event { + HIPRIO_QUEUE_EVENT => vrings[0].get_mut(), + REQ_QUEUE_EVENT => vrings[1].get_mut(), + _ => return Err(new_unexpected_error("failed to handle unknown event", None)), + }; + if self.event_idx { + // If EVENT_IDX is enabled, we could keep calling process_queue() + // until it stops finding new request on the queue. + loop { + vring_state.disable_notification().unwrap(); + self.process_queue_serial(&mut vring_state)?; + if !vring_state.enable_notification().unwrap() { + break; + } + } + } else { + // Without EVENT_IDX, a single call is enough. + self.process_queue_serial(&mut vring_state)?; + } + Ok(()) + } + + /// Forwards filesystem messages to specific functions and + /// returns the filesystem request execution result. + fn process_queue_serial(&self, _vring_state: &mut VringState) -> Result { + unimplemented!() + } +} + +/// VhostUserFsBackend is a structure that implements the VhostUserBackend trait +/// and implements concrete services for the vhost user backend server. +pub struct VhostUserFsBackend { + tag: Option, + thread: RwLock, +} + +#[allow(dead_code)] +impl VhostUserFsBackend { + pub fn new(tag: Option) -> Result { + let thread = RwLock::new(VhostUserFsThread::new()?); + Ok(VhostUserFsBackend { thread, tag }) + } +} + +/// VirtioFsConfig will be serialized and used as +/// the return value of get_config function in the VhostUserBackend trait. +#[repr(C)] +#[derive(Clone, Copy)] +struct VirtioFsConfig { + tag: [u8; MAX_TAG_LEN], + num_request_queues: Le32, +} + +unsafe impl ByteValued for VirtioFsConfig {} + +impl VhostUserBackend for VhostUserFsBackend { + type Bitmap = (); + type Vring = VringMutex; + + /// Get number of queues supported. + fn num_queues(&self) -> usize { + NUM_QUEUES + } + + /// Get maximum queue size supported. + fn max_queue_size(&self) -> usize { + QUEUE_SIZE + } + + /// Get available virtio features. + fn features(&self) -> u64 { + // Align to the virtiofsd's features here. + 1 << VIRTIO_F_VERSION_1 + | 1 << VIRTIO_RING_F_INDIRECT_DESC + | 1 << VIRTIO_RING_F_EVENT_IDX + | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() + } + + /// Get available vhost protocol features. + fn protocol_features(&self) -> VhostUserProtocolFeatures { + // Align to the virtiofsd's protocol features here. + let mut protocol_features = VhostUserProtocolFeatures::MQ + | VhostUserProtocolFeatures::BACKEND_REQ + | VhostUserProtocolFeatures::BACKEND_SEND_FD + | VhostUserProtocolFeatures::REPLY_ACK + | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS; + if self.tag.is_some() { + protocol_features |= VhostUserProtocolFeatures::CONFIG; + } + protocol_features + } + + /// Enable or disabled the virtio EVENT_IDX feature. + fn set_event_idx(&self, enabled: bool) { + self.thread.write().unwrap().event_idx = enabled; + } + + /// Get virtio device configuration. + fn get_config(&self, offset: u32, size: u32) -> Vec { + let tag = self + .tag + .as_ref() + .expect("did not expect read of config if tag is not set."); + let mut fixed_len_tag = [0; MAX_TAG_LEN]; + fixed_len_tag[0..tag.len()].copy_from_slice(tag.as_bytes()); + let config = VirtioFsConfig { + tag: fixed_len_tag, + num_request_queues: Le32::from(REQUEST_QUEUES as u32), + }; + let mut result: Vec<_> = config + .as_slice() + .iter() + .skip(offset as usize) + .take(size as usize) + .copied() + .collect(); + result.resize(size as usize, 0); + result + } + + /// Update guest memory regions. + fn update_memory(&self, mem: GuestMemoryAtomic) -> io::Result<()> { + self.thread.write().unwrap().mem = Some(mem); + Ok(()) + } + + /// Set handler for communicating with the frontend by the backend communication channel. + fn set_backend_req_fd(&self, vu_req: Backend) { + self.thread.write().unwrap().vu_req = Some(vu_req); + } + + /// Provide an optional exit EventFd for the specified worker thread. + fn exit_event(&self, _thread_index: usize) -> Option { + Some( + self.thread + .read() + .unwrap() + .kill_event_fd + .try_clone() + .unwrap(), + ) + } + + /// Handle IO events for backend registered file descriptors. + fn handle_event( + &self, + device_event: u16, + evset: EventSet, + vrings: &[Self::Vring], + _thread_id: usize, + ) -> io::Result<()> { + if evset != EventSet::IN { + return Err(new_unexpected_error( + "failed to handle handle event other than input event", + None, + ) + .into()); + } + let thread = self.thread.read().unwrap(); + thread + .handle_event_serial(device_event, vrings) + .map_err(|err| err.into()) + } +} diff --git a/integrations/virtiofs/src/virtiofs_util.rs b/integrations/virtiofs/src/virtiofs_util.rs new file mode 100644 index 000000000000..f797c8dacb4a --- /dev/null +++ b/integrations/virtiofs/src/virtiofs_util.rs @@ -0,0 +1,249 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cmp::min; +use std::collections::VecDeque; +use std::io::Read; +use std::io::Write; +use std::io::{self}; +use std::mem::size_of; +use std::mem::MaybeUninit; +use std::ops::Deref; +use std::ptr::copy_nonoverlapping; + +use virtio_queue::DescriptorChain; +use vm_memory::bitmap::Bitmap; +use vm_memory::bitmap::BitmapSlice; +use vm_memory::Address; +use vm_memory::ByteValued; +use vm_memory::GuestMemory; +use vm_memory::GuestMemoryMmap; +use vm_memory::GuestMemoryRegion; +use vm_memory::VolatileMemory; +use vm_memory::VolatileSlice; + +use crate::error::*; + +/// Used to consume and use data areas in shared memory between host and VMs. +struct DescriptorChainConsumer<'a, B> { + buffers: VecDeque>, + bytes_consumed: usize, +} + +impl<'a, B: BitmapSlice> DescriptorChainConsumer<'a, B> { + fn bytes_consumed(&self) -> usize { + self.bytes_consumed + } + + fn consume(&mut self, count: usize, f: F) -> Result + where + F: FnOnce(&[&VolatileSlice]) -> Result, + { + let mut len = 0; + let mut bufs = Vec::with_capacity(self.buffers.len()); + for vs in &self.buffers { + if len >= count { + break; + } + bufs.push(vs); + let remain = count - len; + if remain < vs.len() { + len += remain; + } else { + len += vs.len(); + } + } + if bufs.is_empty() { + return Ok(0); + } + let bytes_consumed = f(&bufs)?; + let total_bytes_consumed = + self.bytes_consumed + .checked_add(bytes_consumed) + .ok_or(new_vhost_user_fs_error( + "the combined length of all the buffers in DescriptorChain would overflow", + None, + ))?; + let mut remain = bytes_consumed; + while let Some(vs) = self.buffers.pop_front() { + if remain < vs.len() { + self.buffers.push_front(vs.offset(remain).unwrap()); + break; + } + remain -= vs.len(); + } + self.bytes_consumed = total_bytes_consumed; + Ok(bytes_consumed) + } +} + +/// Provides a high-level interface for reading data in shared memory sequences. +pub struct Reader<'a, B = ()> { + buffer: DescriptorChainConsumer<'a, B>, +} + +#[allow(dead_code)] +impl<'a, B: Bitmap + BitmapSlice + 'static> Reader<'a, B> { + pub fn new( + mem: &'a GuestMemoryMmap, + desc_chain: DescriptorChain, + ) -> Result> + where + M: Deref, + M::Target: GuestMemory + Sized, + { + let mut len: usize = 0; + let buffers = desc_chain + .readable() + .map(|desc| { + len = len + .checked_add(desc.len() as usize) + .ok_or(new_vhost_user_fs_error( + "the combined length of all the buffers in DescriptorChain would overflow", + None, + ))?; + let region = mem.find_region(desc.addr()).ok_or(new_vhost_user_fs_error( + "no memory region for this address range", + None, + ))?; + let offset = desc + .addr() + .checked_sub(region.start_addr().raw_value()) + .unwrap(); + region + .deref() + .get_slice(offset.raw_value() as usize, desc.len() as usize) + .map_err(|err| { + new_vhost_user_fs_error("volatile memory error", Some(err.into())) + }) + }) + .collect::>>>()?; + Ok(Reader { + buffer: DescriptorChainConsumer { + buffers, + bytes_consumed: 0, + }, + }) + } + + pub fn read_obj(&mut self) -> io::Result { + let mut obj = MaybeUninit::::uninit(); + let buf = + unsafe { std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::()) }; + self.read_exact(buf)?; + Ok(unsafe { obj.assume_init() }) + } +} + +impl<'a, B: BitmapSlice> io::Read for Reader<'a, B> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.buffer + .consume(buf.len(), |bufs| { + let mut rem = buf; + let mut total = 0; + for vs in bufs { + let copy_len = min(rem.len(), vs.len()); + unsafe { + copy_nonoverlapping(vs.ptr_guard().as_ptr(), rem.as_mut_ptr(), copy_len); + } + rem = &mut rem[copy_len..]; + total += copy_len; + } + Ok(total) + }) + .map_err(|err| err.into()) + } +} + +/// Provides a high-level interface for writing data in shared memory sequences. +pub struct Writer<'a, B = ()> { + buffer: DescriptorChainConsumer<'a, B>, +} + +#[allow(dead_code)] +impl<'a, B: Bitmap + BitmapSlice + 'static> Writer<'a, B> { + pub fn new( + mem: &'a GuestMemoryMmap, + desc_chain: DescriptorChain, + ) -> Result> + where + M: Deref, + M::Target: GuestMemory + Sized, + { + let mut len: usize = 0; + let buffers = desc_chain + .writable() + .map(|desc| { + len = len + .checked_add(desc.len() as usize) + .ok_or(new_vhost_user_fs_error( + "the combined length of all the buffers in DescriptorChain would overflow", + None, + ))?; + let region = mem.find_region(desc.addr()).ok_or(new_vhost_user_fs_error( + "no memory region for this address range", + None, + ))?; + let offset = desc + .addr() + .checked_sub(region.start_addr().raw_value()) + .unwrap(); + region + .deref() + .get_slice(offset.raw_value() as usize, desc.len() as usize) + .map_err(|err| { + new_vhost_user_fs_error("volatile memory error", Some(err.into())) + }) + }) + .collect::>>>()?; + Ok(Writer { + buffer: DescriptorChainConsumer { + buffers, + bytes_consumed: 0, + }, + }) + } + + pub fn bytes_written(&self) -> usize { + self.buffer.bytes_consumed() + } +} + +impl<'a, B: BitmapSlice> Write for Writer<'a, B> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.buffer + .consume(buf.len(), |bufs| { + let mut rem = buf; + let mut total = 0; + for vs in bufs { + let copy_len = min(rem.len(), vs.len()); + unsafe { + copy_nonoverlapping(rem.as_ptr(), vs.ptr_guard_mut().as_ptr(), copy_len); + } + vs.bitmap().mark_dirty(0, copy_len); + rem = &rem[copy_len..]; + total += copy_len; + } + Ok(total) + }) + .map_err(|err| err.into()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} From e93835c412c62f9b5464b77d13edf25029b22ef9 Mon Sep 17 00:00:00 2001 From: zjregee Date: Thu, 13 Jun 2024 16:44:03 +0800 Subject: [PATCH 2/3] remove virtiofs bin --- bin/ovfs/Cargo.lock | 225 ----------------------------- bin/ovfs/Cargo.toml | 32 ----- bin/ovfs/DEPENDENCIES.rust.tsv | 26 ---- bin/ovfs/src/error.rs | 83 ----------- bin/ovfs/src/main.rs | 24 ---- bin/ovfs/src/virtiofs.rs | 240 ------------------------------- bin/ovfs/src/virtiofs_utils.rs | 249 --------------------------------- 7 files changed, 879 deletions(-) delete mode 100644 bin/ovfs/Cargo.lock delete mode 100644 bin/ovfs/Cargo.toml delete mode 100644 bin/ovfs/DEPENDENCIES.rust.tsv delete mode 100644 bin/ovfs/src/error.rs delete mode 100644 bin/ovfs/src/main.rs delete mode 100644 bin/ovfs/src/virtiofs.rs delete mode 100644 bin/ovfs/src/virtiofs_utils.rs diff --git a/bin/ovfs/Cargo.lock b/bin/ovfs/Cargo.lock deleted file mode 100644 index 8d851d460b9f..000000000000 --- a/bin/ovfs/Cargo.lock +++ /dev/null @@ -1,225 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "ovfs" -version = "0.1.0" -dependencies = [ - "anyhow", - "libc", - "snafu", - "vhost", - "vhost-user-backend", - "virtio-bindings", - "virtio-queue", - "vm-memory", - "vmm-sys-util", -] - -[[package]] -name = "proc-macro2" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "snafu" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418b8136fec49956eba89be7da2847ec1909df92a9ae4178b5ff0ff092c8d95e" -dependencies = [ - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a4812a669da00d17d8266a0439eddcacbc88b17f732f927e52eeb9d196f7fb5" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "2.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vhost" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be08d1166d41a78861ad50212ab3f9eca0729c349ac3a7a8f557c62406b87cc" -dependencies = [ - "bitflags 2.5.0", - "libc", - "vm-memory", - "vmm-sys-util", -] - -[[package]] -name = "vhost-user-backend" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76401f5c520d068ccb31eefbc88fa5b526039747ec612cb33a5f9c57a263199" -dependencies = [ - "libc", - "log", - "vhost", - "virtio-bindings", - "virtio-queue", - "vm-memory", - "vmm-sys-util", -] - -[[package]] -name = "virtio-bindings" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878bcb1b2812a10c30d53b0ed054999de3d98f25ece91fc173973f9c57aaae86" - -[[package]] -name = "virtio-queue" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3f69a13d6610db9312acbb438b0390362af905d37634a2106be70c0f734986d" -dependencies = [ - "log", - "virtio-bindings", - "vm-memory", - "vmm-sys-util", -] - -[[package]] -name = "vm-memory" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3aba5064cc5f6f7740cddc8dae34d2d9a311cac69b60d942af7f3ab8fc49f4" -dependencies = [ - "arc-swap", - "libc", - "thiserror", - "winapi", -] - -[[package]] -name = "vmm-sys-util" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/bin/ovfs/Cargo.toml b/bin/ovfs/Cargo.toml deleted file mode 100644 index 9903fbf3f99e..000000000000 --- a/bin/ovfs/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -[package] -name = "ovfs" -version = "0.1.0" -edition = "2021" - -[dependencies] -snafu = "0.8.3" -libc = "0.2.139" -vhost = "0.11.0" -virtio-queue = "0.11.0" -vmm-sys-util = "0.12.1" -virtio-bindings = "0.2.1" -vhost-user-backend = "0.14.0" -anyhow = { version = "1.0.86", features = ["std"] } -vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic"] } diff --git a/bin/ovfs/DEPENDENCIES.rust.tsv b/bin/ovfs/DEPENDENCIES.rust.tsv deleted file mode 100644 index 22c12d17511c..000000000000 --- a/bin/ovfs/DEPENDENCIES.rust.tsv +++ /dev/null @@ -1,26 +0,0 @@ -crate Apache-2.0 BSD-3-Clause MIT Unicode-DFS-2016 Unlicensed -anyhow@1.0.86 X X -arc-swap@1.7.1 X X -bitflags@1.3.2 X X -bitflags@2.5.0 X X -heck@0.5.0 X X -libc@0.2.155 X X -log@0.4.21 X X -ovfs@0.1.0 X -proc-macro2@1.0.85 X X -quote@1.0.36 X X -snafu@0.8.3 X X -snafu-derive@0.8.3 X X -syn@2.0.66 X X -thiserror@1.0.61 X X -thiserror-impl@1.0.61 X X -unicode-ident@1.0.12 X X X -vhost@0.11.0 X X -vhost-user-backend@0.14.0 X -virtio-bindings@0.2.2 X X -virtio-queue@0.11.0 X X -vm-memory@0.14.1 X X -vmm-sys-util@0.12.1 X -winapi@0.3.9 X X -winapi-i686-pc-windows-gnu@0.4.0 X X -winapi-x86_64-pc-windows-gnu@0.4.0 X X diff --git a/bin/ovfs/src/error.rs b/bin/ovfs/src/error.rs deleted file mode 100644 index d8c0ff125c88..000000000000 --- a/bin/ovfs/src/error.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::io; - -use anyhow::Error as AnyError; -use snafu::prelude::Snafu; - -/// Error is a error struct returned by all ovfs functions. -#[derive(Debug, Snafu)] -#[non_exhaustive] -pub enum Error { - #[snafu(display("Vhost user fs error: {}, source: {:?}", message, source))] - VhostUserFsError { - message: String, - #[snafu(source(false))] - source: Option, - }, - #[snafu(display("Unexpected error: {}, source: {:?}", message, source))] - Unexpected { - message: String, - #[snafu(source(false))] - source: Option, - }, -} - -impl From for io::Error { - fn from(error: Error) -> io::Error { - match error { - Error::VhostUserFsError { message, source } => { - let message = format!("Vhost user fs error: {}", message); - match source { - Some(source) => io::Error::new( - io::ErrorKind::Other, - format!("{}, source: {:?}", message, source), - ), - None => io::Error::new(io::ErrorKind::Other, message), - } - } - Error::Unexpected { message, source } => { - let message = format!("Unexpected error: {}", message); - match source { - Some(source) => io::Error::new( - io::ErrorKind::Other, - format!("{}, source: {:?}", message, source), - ), - None => io::Error::new(io::ErrorKind::Other, message), - } - } - } - } -} - -/// Result is a result wrapper in ovfs. -pub type Result = std::result::Result; - -pub fn new_vhost_user_fs_error(message: &str, source: Option) -> Error { - Error::VhostUserFsError { - message: message.to_string(), - source, - } -} - -pub fn new_unexpected_error(message: &str, source: Option) -> Error { - Error::Unexpected { - message: message.to_string(), - source, - } -} diff --git a/bin/ovfs/src/main.rs b/bin/ovfs/src/main.rs deleted file mode 100644 index d38f87407fd6..000000000000 --- a/bin/ovfs/src/main.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -mod error; -mod virtiofs; -mod virtiofs_utils; - -fn main() { - unimplemented!() -} diff --git a/bin/ovfs/src/virtiofs.rs b/bin/ovfs/src/virtiofs.rs deleted file mode 100644 index a7e33e22751d..000000000000 --- a/bin/ovfs/src/virtiofs.rs +++ /dev/null @@ -1,240 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::io; -use std::sync::RwLock; - -use vhost::vhost_user::message::VhostUserProtocolFeatures; -use vhost::vhost_user::message::VhostUserVirtioFeatures; -use vhost::vhost_user::Backend; -use vhost_user_backend::VhostUserBackend; -use vhost_user_backend::VringMutex; -use vhost_user_backend::VringState; -use vhost_user_backend::VringT; -use virtio_bindings::bindings::virtio_config::VIRTIO_F_VERSION_1; -use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; -use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_INDIRECT_DESC; -use vm_memory::ByteValued; -use vm_memory::GuestMemoryAtomic; -use vm_memory::GuestMemoryMmap; -use vm_memory::Le32; -use vmm_sys_util::epoll::EventSet; -use vmm_sys_util::eventfd::EventFd; - -use crate::error::*; - -/// Marks an event from the high priority queue. -const HIPRIO_QUEUE_EVENT: u16 = 0; -/// Marks an event from the request queue. -const REQ_QUEUE_EVENT: u16 = 1; -/// The maximum number of bytes in VirtioFsConfig tag field. -const MAX_TAG_LEN: usize = 36; -/// The maximum queue size supported. -const QUEUE_SIZE: usize = 32768; -/// The number of request queues supported. -/// The vitrofs spec allows for multiple request queues, but we'll only support one. -const REQUEST_QUEUES: usize = 1; -/// In addition to request queues there is one high priority queue. -const NUM_QUEUES: usize = REQUEST_QUEUES + 1; - -/// VhostUserFsThread represents the actual worker process used to handle file system requests from VMs. -struct VhostUserFsThread { - mem: Option>, - vu_req: Option, - event_idx: bool, - kill_event_fd: EventFd, -} - -impl VhostUserFsThread { - fn new() -> Result { - let event_fd = EventFd::new(libc::EFD_NONBLOCK).map_err(|err| { - new_unexpected_error("failed to create kill eventfd", Some(err.into())) - })?; - Ok(VhostUserFsThread { - mem: None, - vu_req: None, - event_idx: false, - kill_event_fd: event_fd, - }) - } - - /// Process filesystem requests one at a time in a serialized manner. - fn handle_event_serial(&self, device_event: u16, vrings: &[VringMutex]) -> Result<()> { - let mut vring_state = match device_event { - HIPRIO_QUEUE_EVENT => vrings[0].get_mut(), - REQ_QUEUE_EVENT => vrings[1].get_mut(), - _ => return Err(new_unexpected_error("failed to handle unknown event", None)), - }; - if self.event_idx { - // If EVENT_IDX is enabled, we could keep calling process_queue() - // until it stops finding new request on the queue. - loop { - vring_state.disable_notification().unwrap(); - self.process_queue_serial(&mut vring_state)?; - if !vring_state.enable_notification().unwrap() { - break; - } - } - } else { - // Without EVENT_IDX, a single call is enough. - self.process_queue_serial(&mut vring_state)?; - } - Ok(()) - } - - /// Forwards filesystem messages to specific functions and - /// returns the filesystem request execution result. - fn process_queue_serial(&self, _vring_state: &mut VringState) -> Result { - unimplemented!() - } -} - -/// VhostUserFsBackend is a structure that implements the VhostUserBackend trait -/// and implements concrete services for the vhost user backend server. -pub struct VhostUserFsBackend { - tag: Option, - thread: RwLock, -} - -#[allow(dead_code)] -impl VhostUserFsBackend { - pub fn new(tag: Option) -> Result { - let thread = RwLock::new(VhostUserFsThread::new()?); - Ok(VhostUserFsBackend { thread, tag }) - } -} - -/// VirtioFsConfig will be serialized and used as -/// the return value of get_config function in the VhostUserBackend trait. -#[repr(C)] -#[derive(Clone, Copy)] -struct VirtioFsConfig { - tag: [u8; MAX_TAG_LEN], - num_request_queues: Le32, -} - -unsafe impl ByteValued for VirtioFsConfig {} - -impl VhostUserBackend for VhostUserFsBackend { - type Bitmap = (); - type Vring = VringMutex; - - /// Get number of queues supported. - fn num_queues(&self) -> usize { - NUM_QUEUES - } - - /// Get maximum queue size supported. - fn max_queue_size(&self) -> usize { - QUEUE_SIZE - } - - /// Get available virtio features. - fn features(&self) -> u64 { - // Align to the virtiofsd's features here. - 1 << VIRTIO_F_VERSION_1 - | 1 << VIRTIO_RING_F_INDIRECT_DESC - | 1 << VIRTIO_RING_F_EVENT_IDX - | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() - } - - /// Get available vhost protocol features. - fn protocol_features(&self) -> VhostUserProtocolFeatures { - // Align to the virtiofsd's protocol features here. - let mut protocol_features = VhostUserProtocolFeatures::MQ - | VhostUserProtocolFeatures::BACKEND_REQ - | VhostUserProtocolFeatures::BACKEND_SEND_FD - | VhostUserProtocolFeatures::REPLY_ACK - | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS; - if self.tag.is_some() { - protocol_features |= VhostUserProtocolFeatures::CONFIG; - } - protocol_features - } - - /// Enable or disabled the virtio EVENT_IDX feature. - fn set_event_idx(&self, enabled: bool) { - self.thread.write().unwrap().event_idx = enabled; - } - - /// Get virtio device configuration. - fn get_config(&self, offset: u32, size: u32) -> Vec { - let tag = self - .tag - .as_ref() - .expect("did not expect read of config if tag is not set."); - let mut fixed_len_tag = [0; MAX_TAG_LEN]; - fixed_len_tag[0..tag.len()].copy_from_slice(tag.as_bytes()); - let config = VirtioFsConfig { - tag: fixed_len_tag, - num_request_queues: Le32::from(REQUEST_QUEUES as u32), - }; - let mut result: Vec<_> = config - .as_slice() - .iter() - .skip(offset as usize) - .take(size as usize) - .copied() - .collect(); - result.resize(size as usize, 0); - result - } - - /// Update guest memory regions. - fn update_memory(&self, mem: GuestMemoryAtomic) -> io::Result<()> { - self.thread.write().unwrap().mem = Some(mem); - Ok(()) - } - - /// Set handler for communicating with the frontend by the backend communication channel. - fn set_backend_req_fd(&self, vu_req: Backend) { - self.thread.write().unwrap().vu_req = Some(vu_req); - } - - /// Provide an optional exit EventFd for the specified worker thread. - fn exit_event(&self, _thread_index: usize) -> Option { - Some( - self.thread - .read() - .unwrap() - .kill_event_fd - .try_clone() - .unwrap(), - ) - } - - /// Handle IO events for backend registered file descriptors. - fn handle_event( - &self, - device_event: u16, - evset: EventSet, - vrings: &[Self::Vring], - _thread_id: usize, - ) -> io::Result<()> { - if evset != EventSet::IN { - return Err(new_unexpected_error( - "failed to handle handle event other than input event", - None, - ) - .into()); - } - let thread = self.thread.read().unwrap(); - thread - .handle_event_serial(device_event, vrings) - .map_err(|err| err.into()) - } -} diff --git a/bin/ovfs/src/virtiofs_utils.rs b/bin/ovfs/src/virtiofs_utils.rs deleted file mode 100644 index f797c8dacb4a..000000000000 --- a/bin/ovfs/src/virtiofs_utils.rs +++ /dev/null @@ -1,249 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cmp::min; -use std::collections::VecDeque; -use std::io::Read; -use std::io::Write; -use std::io::{self}; -use std::mem::size_of; -use std::mem::MaybeUninit; -use std::ops::Deref; -use std::ptr::copy_nonoverlapping; - -use virtio_queue::DescriptorChain; -use vm_memory::bitmap::Bitmap; -use vm_memory::bitmap::BitmapSlice; -use vm_memory::Address; -use vm_memory::ByteValued; -use vm_memory::GuestMemory; -use vm_memory::GuestMemoryMmap; -use vm_memory::GuestMemoryRegion; -use vm_memory::VolatileMemory; -use vm_memory::VolatileSlice; - -use crate::error::*; - -/// Used to consume and use data areas in shared memory between host and VMs. -struct DescriptorChainConsumer<'a, B> { - buffers: VecDeque>, - bytes_consumed: usize, -} - -impl<'a, B: BitmapSlice> DescriptorChainConsumer<'a, B> { - fn bytes_consumed(&self) -> usize { - self.bytes_consumed - } - - fn consume(&mut self, count: usize, f: F) -> Result - where - F: FnOnce(&[&VolatileSlice]) -> Result, - { - let mut len = 0; - let mut bufs = Vec::with_capacity(self.buffers.len()); - for vs in &self.buffers { - if len >= count { - break; - } - bufs.push(vs); - let remain = count - len; - if remain < vs.len() { - len += remain; - } else { - len += vs.len(); - } - } - if bufs.is_empty() { - return Ok(0); - } - let bytes_consumed = f(&bufs)?; - let total_bytes_consumed = - self.bytes_consumed - .checked_add(bytes_consumed) - .ok_or(new_vhost_user_fs_error( - "the combined length of all the buffers in DescriptorChain would overflow", - None, - ))?; - let mut remain = bytes_consumed; - while let Some(vs) = self.buffers.pop_front() { - if remain < vs.len() { - self.buffers.push_front(vs.offset(remain).unwrap()); - break; - } - remain -= vs.len(); - } - self.bytes_consumed = total_bytes_consumed; - Ok(bytes_consumed) - } -} - -/// Provides a high-level interface for reading data in shared memory sequences. -pub struct Reader<'a, B = ()> { - buffer: DescriptorChainConsumer<'a, B>, -} - -#[allow(dead_code)] -impl<'a, B: Bitmap + BitmapSlice + 'static> Reader<'a, B> { - pub fn new( - mem: &'a GuestMemoryMmap, - desc_chain: DescriptorChain, - ) -> Result> - where - M: Deref, - M::Target: GuestMemory + Sized, - { - let mut len: usize = 0; - let buffers = desc_chain - .readable() - .map(|desc| { - len = len - .checked_add(desc.len() as usize) - .ok_or(new_vhost_user_fs_error( - "the combined length of all the buffers in DescriptorChain would overflow", - None, - ))?; - let region = mem.find_region(desc.addr()).ok_or(new_vhost_user_fs_error( - "no memory region for this address range", - None, - ))?; - let offset = desc - .addr() - .checked_sub(region.start_addr().raw_value()) - .unwrap(); - region - .deref() - .get_slice(offset.raw_value() as usize, desc.len() as usize) - .map_err(|err| { - new_vhost_user_fs_error("volatile memory error", Some(err.into())) - }) - }) - .collect::>>>()?; - Ok(Reader { - buffer: DescriptorChainConsumer { - buffers, - bytes_consumed: 0, - }, - }) - } - - pub fn read_obj(&mut self) -> io::Result { - let mut obj = MaybeUninit::::uninit(); - let buf = - unsafe { std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::()) }; - self.read_exact(buf)?; - Ok(unsafe { obj.assume_init() }) - } -} - -impl<'a, B: BitmapSlice> io::Read for Reader<'a, B> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.buffer - .consume(buf.len(), |bufs| { - let mut rem = buf; - let mut total = 0; - for vs in bufs { - let copy_len = min(rem.len(), vs.len()); - unsafe { - copy_nonoverlapping(vs.ptr_guard().as_ptr(), rem.as_mut_ptr(), copy_len); - } - rem = &mut rem[copy_len..]; - total += copy_len; - } - Ok(total) - }) - .map_err(|err| err.into()) - } -} - -/// Provides a high-level interface for writing data in shared memory sequences. -pub struct Writer<'a, B = ()> { - buffer: DescriptorChainConsumer<'a, B>, -} - -#[allow(dead_code)] -impl<'a, B: Bitmap + BitmapSlice + 'static> Writer<'a, B> { - pub fn new( - mem: &'a GuestMemoryMmap, - desc_chain: DescriptorChain, - ) -> Result> - where - M: Deref, - M::Target: GuestMemory + Sized, - { - let mut len: usize = 0; - let buffers = desc_chain - .writable() - .map(|desc| { - len = len - .checked_add(desc.len() as usize) - .ok_or(new_vhost_user_fs_error( - "the combined length of all the buffers in DescriptorChain would overflow", - None, - ))?; - let region = mem.find_region(desc.addr()).ok_or(new_vhost_user_fs_error( - "no memory region for this address range", - None, - ))?; - let offset = desc - .addr() - .checked_sub(region.start_addr().raw_value()) - .unwrap(); - region - .deref() - .get_slice(offset.raw_value() as usize, desc.len() as usize) - .map_err(|err| { - new_vhost_user_fs_error("volatile memory error", Some(err.into())) - }) - }) - .collect::>>>()?; - Ok(Writer { - buffer: DescriptorChainConsumer { - buffers, - bytes_consumed: 0, - }, - }) - } - - pub fn bytes_written(&self) -> usize { - self.buffer.bytes_consumed() - } -} - -impl<'a, B: BitmapSlice> Write for Writer<'a, B> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.buffer - .consume(buf.len(), |bufs| { - let mut rem = buf; - let mut total = 0; - for vs in bufs { - let copy_len = min(rem.len(), vs.len()); - unsafe { - copy_nonoverlapping(rem.as_ptr(), vs.ptr_guard_mut().as_ptr(), copy_len); - } - vs.bitmap().mark_dirty(0, copy_len); - rem = &rem[copy_len..]; - total += copy_len; - } - Ok(total) - }) - .map_err(|err| err.into()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} From 1046335326db73f83c8422b3e9c956c02eb864ba Mon Sep 17 00:00:00 2001 From: zjregee Date: Thu, 13 Jun 2024 16:50:33 +0800 Subject: [PATCH 3/3] modify ci --- .github/dependabot.yml | 6 --- ..._bin_ovfs.yml => ci_integration_fuse3.yml} | 8 +-- .github/workflows/ci_integration_virtiofs.yml | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) rename .github/workflows/{ci_bin_ovfs.yml => ci_integration_fuse3.yml} (89%) create mode 100644 .github/workflows/ci_integration_virtiofs.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d056e19b7e90..4e4a81173ece 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -47,12 +47,6 @@ updates: schedule: interval: "monthly" - - package-ecosystem: "cargo" - directory: "/bin/ovfs" - open-pull-requests-limit: 1 - schedule: - interval: "monthly" - - package-ecosystem: "cargo" directory: "/integrations/dav-server" open-pull-requests-limit: 1 diff --git a/.github/workflows/ci_bin_ovfs.yml b/.github/workflows/ci_integration_fuse3.yml similarity index 89% rename from .github/workflows/ci_bin_ovfs.yml rename to .github/workflows/ci_integration_fuse3.yml index 8c967c2aa16d..63a878aa7df7 100644 --- a/.github/workflows/ci_bin_ovfs.yml +++ b/.github/workflows/ci_integration_fuse3.yml @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -name: Ovfs CI +name: Integration Fuse3 CI on: push: @@ -25,9 +25,9 @@ on: branches: - main paths: - - "bin/ovfs/**" + - "integrations/fuse3/**" - "core/**" - - ".github/workflows/ci_bin_ovfs.yml" + - ".github/workflows/ci_integration_fuse3.yml" concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} @@ -47,5 +47,5 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Cargo clippy - working-directory: bin/ovfs + working-directory: integrations/fuse3 run: cargo clippy --all-targets --all-features -- -D warnings diff --git a/.github/workflows/ci_integration_virtiofs.yml b/.github/workflows/ci_integration_virtiofs.yml new file mode 100644 index 000000000000..648c69182132 --- /dev/null +++ b/.github/workflows/ci_integration_virtiofs.yml @@ -0,0 +1,51 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Integration Virtiofs CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + paths: + - "integrations/virtiofs/**" + - "core/**" + - ".github/workflows/ci_integration_virtiofs.yml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +jobs: + check_clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Rust toolchain + uses: ./.github/actions/setup + with: + need-rocksdb: true + need-protoc: true + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Cargo clippy + working-directory: integrations/virtiofs + run: cargo clippy --all-targets --all-features -- -D warnings