mirror of
https://github.com/rust-vmm/vhost-device.git
synced 2026-01-07 11:37:40 +00:00
vsock: run rustfmt
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This commit is contained in:
parent
3e1ea87bdc
commit
f77506a809
@ -18,9 +18,6 @@ use std::{
|
||||
thread,
|
||||
};
|
||||
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use crate::vhu_vsock::VsockProxyInfo;
|
||||
use crate::vhu_vsock::{BackendType, CidMap, VhostUserVsockBackend, VsockConfig};
|
||||
use clap::{Args, Parser};
|
||||
use figment::{
|
||||
providers::{Format, Yaml},
|
||||
@ -32,6 +29,10 @@ use thiserror::Error as ThisError;
|
||||
use vhost_user_backend::VhostUserDaemon;
|
||||
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
|
||||
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use crate::vhu_vsock::VsockProxyInfo;
|
||||
use crate::vhu_vsock::{BackendType, CidMap, VhostUserVsockBackend, VsockConfig};
|
||||
|
||||
const DEFAULT_GUEST_CID: u64 = 3;
|
||||
const DEFAULT_TX_BUFFER_SIZE: u32 = 64 * 1024;
|
||||
const DEFAULT_QUEUE_SIZE: usize = 1024;
|
||||
@ -71,7 +72,8 @@ enum BackendError {
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
struct VsockParam {
|
||||
/// Context identifier of the guest which uniquely identifies the device for its lifetime.
|
||||
/// Context identifier of the guest which uniquely identifies the device for
|
||||
/// its lifetime.
|
||||
#[arg(
|
||||
long,
|
||||
default_value_t = DEFAULT_GUEST_CID,
|
||||
@ -80,7 +82,8 @@ struct VsockParam {
|
||||
)]
|
||||
guest_cid: u64,
|
||||
|
||||
/// Unix socket to which a hypervisor connects to and sets up the control path with the device.
|
||||
/// Unix socket to which a hypervisor connects to and sets up the control
|
||||
/// path with the device.
|
||||
#[arg(long, conflicts_with = "config", conflicts_with = "vm")]
|
||||
socket: PathBuf,
|
||||
|
||||
@ -129,7 +132,8 @@ struct VsockParam {
|
||||
queue_size: usize,
|
||||
|
||||
/// The list of group names to which the device belongs.
|
||||
/// A group is a set of devices that allow sibling communication between their guests.
|
||||
/// A group is a set of devices that allow sibling communication between
|
||||
/// their guests.
|
||||
#[arg(
|
||||
long,
|
||||
default_value_t = String::from(DEFAULT_GROUP_NAME),
|
||||
@ -160,23 +164,39 @@ struct VsockArgs {
|
||||
#[command(flatten)]
|
||||
param: Option<VsockParam>,
|
||||
|
||||
/// Device parameters corresponding to a VM in the form of comma separated key=value pairs.
|
||||
/// The allowed keys are: guest_cid, socket, uds_path, tx_buffer_size, queue_size and group.
|
||||
/// Device parameters corresponding to a VM in the form of comma separated
|
||||
/// key=value pairs.
|
||||
///
|
||||
/// The allowed keys are: guest_cid, socket, uds_path, tx_buffer_size,
|
||||
/// queue_size and group.
|
||||
///
|
||||
/// Example:
|
||||
/// --vm guest-cid=3,socket=/tmp/vhost3.socket,uds-path=/tmp/vm3.vsock,tx-buffer-size=65536,queue-size=1024,groups=group1+group2
|
||||
/// Multiple instances of this argument can be provided to configure devices for multiple guests.
|
||||
/// --vm guest-cid=3,socket=/tmp/vhost3.socket,uds-path=/tmp/vm3.vsock,
|
||||
/// tx-buffer-size=65536,queue-size=1024,groups=group1+group2
|
||||
///
|
||||
/// Multiple instances of this argument can be provided to configure devices
|
||||
/// for multiple guests.
|
||||
#[cfg(not(feature = "backend_vsock"))]
|
||||
#[arg(long, conflicts_with = "config", verbatim_doc_comment, value_parser = parse_vm_params)]
|
||||
vm: Option<Vec<VsockConfig>>,
|
||||
|
||||
/// Device parameters corresponding to a VM in the form of comma separated key=value pairs.
|
||||
/// The allowed keys are: guest_cid, socket, uds_path, forward_cid, forward_listen, tx_buffer_size, queue_size and group.
|
||||
/// uds_path and (forward_cid, forward_listen) are mutually exclusive. Use uds_path when you want unix domain socket
|
||||
/// backend, otherwise forward_cid, forward_listen for vsock backend.
|
||||
/// Device parameters corresponding to a VM in the form of comma separated
|
||||
/// key=value pairs.
|
||||
///
|
||||
/// The allowed keys are: guest_cid, socket, uds_path, forward_cid,
|
||||
/// forward_listen, tx_buffer_size, queue_size and group. uds_path and
|
||||
/// (forward_cid, forward_listen) are mutually exclusive. Use uds_path when
|
||||
/// you want unix domain socket backend, otherwise forward_cid,
|
||||
/// forward_listen for vsock backend.
|
||||
///
|
||||
/// Example:
|
||||
/// --vm guest-cid=3,socket=/tmp/vhost3.socket,uds-path=/tmp/vm3.vsock,tx-buffer-size=65536,queue-size=1024,groups=group1+group2
|
||||
/// --vm guest-cid=3,socket=/tmp/vhost3.socket,forward-cid=1,forward-listen=9001,queue-size=1024
|
||||
/// Multiple instances of this argument can be provided to configure devices for multiple guests.
|
||||
/// --vm guest-cid=3,socket=/tmp/vhost3.socket,uds-path=/tmp/vm3.vsock,
|
||||
/// tx-buffer-size=65536,queue-size=1024,groups=group1+group2
|
||||
/// --vm guest-cid=3,socket=/tmp/vhost3.socket,forward-cid=1,
|
||||
/// forward-listen=9001,queue-size=1024
|
||||
///
|
||||
/// Multiple instances of this argument can be provided to configure devices
|
||||
/// for multiple guests.
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
#[arg(long, conflicts_with = "config", verbatim_doc_comment, value_parser = parse_vm_params)]
|
||||
vm: Option<Vec<VsockConfig>>,
|
||||
@ -337,7 +357,8 @@ impl TryFrom<VsockArgs> for Vec<VsockConfig> {
|
||||
type Error = CliError;
|
||||
|
||||
fn try_from(cmd_args: VsockArgs) -> Result<Self, CliError> {
|
||||
// we try to use the configuration first, if failed, then fall back to the manual settings.
|
||||
// we try to use the configuration first, if failed, then fall back to the
|
||||
// manual settings.
|
||||
match cmd_args.parse_config() {
|
||||
Some(c) => c,
|
||||
_ => match cmd_args.vm {
|
||||
@ -475,13 +496,13 @@ fn main() {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{fs::File, io::Write, path::Path};
|
||||
|
||||
use assert_matches::assert_matches;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl VsockArgs {
|
||||
fn from_args_unix(
|
||||
guest_cid: u64,
|
||||
@ -964,7 +985,8 @@ mod tests {
|
||||
|
||||
let mut epoll_handlers = daemon.get_epoll_handlers();
|
||||
|
||||
// VhostUserVsockBackend support a single thread that handles the TX and RX queues
|
||||
// VhostUserVsockBackend support a single thread that handles the TX and RX
|
||||
// queues
|
||||
assert_eq!(backend.threads.len(), 1);
|
||||
|
||||
assert_eq!(epoll_handlers.len(), backend.threads.len());
|
||||
|
||||
@ -130,13 +130,14 @@ impl ReadVolatile for StreamType {
|
||||
|
||||
let dst = guard.as_ptr().cast::<libc::c_void>();
|
||||
|
||||
// SAFETY: We got a valid file descriptor from `AsRawFd`. The memory pointed to by `dst` is
|
||||
// valid for writes of length `buf.len() by the invariants upheld by the constructor
|
||||
// of `VolatileSlice`.
|
||||
// SAFETY: We got a valid file descriptor from `AsRawFd`. The memory pointed to
|
||||
// by `dst` is valid for writes of length `buf.len() by the
|
||||
// invariants upheld by the constructor of `VolatileSlice`.
|
||||
let bytes_read = unsafe { libc::read(fd, dst, buf.len()) };
|
||||
|
||||
if bytes_read < 0 {
|
||||
// We don't know if a partial read might have happened, so mark everything as dirty
|
||||
// We don't know if a partial read might have happened, so mark everything as
|
||||
// dirty
|
||||
buf.bitmap().mark_dirty(0, buf.len());
|
||||
|
||||
Err(VolatileMemoryError::IOError(std::io::Error::last_os_error()))
|
||||
@ -165,9 +166,9 @@ impl WriteVolatile for StreamType {
|
||||
|
||||
let src = guard.as_ptr().cast::<libc::c_void>();
|
||||
|
||||
// SAFETY: We got a valid file descriptor from `AsRawFd`. The memory pointed to by `src` is
|
||||
// valid for reads of length `buf.len() by the invariants upheld by the constructor
|
||||
// of `VolatileSlice`.
|
||||
// SAFETY: We got a valid file descriptor from `AsRawFd`. The memory pointed to
|
||||
// by `src` is valid for reads of length `buf.len() by the
|
||||
// invariants upheld by the constructor of `VolatileSlice`.
|
||||
let bytes_written = unsafe { libc::write(fd, src, buf.len()) };
|
||||
|
||||
if bytes_written < 0 {
|
||||
@ -208,11 +209,14 @@ pub(crate) struct VsockThreadBackend {
|
||||
/// Set of allocated local ports.
|
||||
pub local_port_set: HashSet<u32>,
|
||||
tx_buffer_size: u32,
|
||||
/// Maps the guest CID to the corresponding backend. Used for sibling VM communication.
|
||||
/// Maps the guest CID to the corresponding backend. Used for sibling VM
|
||||
/// communication.
|
||||
pub cid_map: Arc<RwLock<CidMap>>,
|
||||
/// Queue of raw vsock packets received from sibling VMs to be sent to the guest.
|
||||
/// Queue of raw vsock packets received from sibling VMs to be sent to the
|
||||
/// guest.
|
||||
pub raw_pkts_queue: Arc<RwLock<RawPktsQ>>,
|
||||
/// Set of groups assigned to the device which it is allowed to communicate with.
|
||||
/// Set of groups assigned to the device which it is allowed to communicate
|
||||
/// with.
|
||||
groups_set: Arc<RwLock<HashSet<String>>>,
|
||||
}
|
||||
|
||||
@ -410,7 +414,8 @@ impl VsockThreadBackend {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deliver a raw vsock packet sent from a sibling VM to the guest vsock driver.
|
||||
/// Deliver a raw vsock packet sent from a sibling VM to the guest vsock
|
||||
/// driver.
|
||||
///
|
||||
/// Returns:
|
||||
/// - `Ok(())` if packet was successfully filled in
|
||||
@ -432,13 +437,16 @@ impl VsockThreadBackend {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle a new guest initiated connection, i.e from the peer, the guest driver.
|
||||
/// Handle a new guest initiated connection, i.e from the peer, the guest
|
||||
/// driver.
|
||||
///
|
||||
/// In case of proxying using unix domain socket, attempts to connect to a host side unix socket
|
||||
/// listening on a path corresponding to the destination port as follows:
|
||||
/// In case of proxying using unix domain socket, attempts to connect to a
|
||||
/// host side unix socket listening on a path corresponding to the
|
||||
/// destination port as follows:
|
||||
/// - "{self.host_sock_path}_{local_port}""
|
||||
///
|
||||
/// In case of proxying using vosck, attempts to connect to the {forward_cid, local_port}
|
||||
/// In case of proxying using vosck, attempts to connect to the
|
||||
/// {forward_cid, local_port}
|
||||
fn handle_new_guest_conn<B: BitmapSlice>(&mut self, pkt: &VsockPacket<B>) {
|
||||
match &self.backend_info {
|
||||
BackendType::UnixDomainSocket(uds_path) => {
|
||||
@ -509,16 +517,18 @@ impl VsockThreadBackend {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use crate::vhu_vsock::VsockProxyInfo;
|
||||
use crate::vhu_vsock::{BackendType, VhostUserVsockBackend, VsockConfig, VSOCK_OP_RW};
|
||||
use std::os::unix::net::UnixListener;
|
||||
|
||||
use tempfile::tempdir;
|
||||
use virtio_vsock::packet::{VsockPacket, PKT_HEADER_SIZE};
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use vsock::{VsockListener, VMADDR_CID_ANY, VMADDR_CID_LOCAL};
|
||||
|
||||
use super::*;
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use crate::vhu_vsock::VsockProxyInfo;
|
||||
use crate::vhu_vsock::{BackendType, VhostUserVsockBackend, VsockConfig, VSOCK_OP_RW};
|
||||
|
||||
const DATA_LEN: usize = 16;
|
||||
const CONN_TX_BUF_SIZE: u32 = 64 * 1024;
|
||||
const QUEUE_SIZE: usize = 1024;
|
||||
|
||||
@ -85,7 +85,8 @@ impl LocalTxBuf {
|
||||
// Increment head by amount of data that has been flushed to the stream
|
||||
self.head += Wrapping(written as u32);
|
||||
|
||||
// If written length is less than the expected length we can try again in the future
|
||||
// If written length is less than the expected length we can try again in the
|
||||
// future
|
||||
if written < len {
|
||||
return Ok(written);
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ use thiserror::Error as ThisError;
|
||||
use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
|
||||
use vhost_user_backend::{VhostUserBackend, VringRwLock};
|
||||
use virtio_bindings::bindings::{
|
||||
virtio_config::VIRTIO_F_NOTIFY_ON_EMPTY, virtio_config::VIRTIO_F_VERSION_1,
|
||||
virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1},
|
||||
virtio_ring::VIRTIO_RING_F_EVENT_IDX,
|
||||
};
|
||||
use vm_memory::{ByteValued, GuestMemoryAtomic, GuestMemoryMmap, Le64};
|
||||
@ -21,8 +21,7 @@ use vmm_sys_util::{
|
||||
eventfd::{EventFd, EFD_NONBLOCK},
|
||||
};
|
||||
|
||||
use crate::thread_backend::RawPktsQ;
|
||||
use crate::vhu_vsock_thread::*;
|
||||
use crate::{thread_backend::RawPktsQ, vhu_vsock_thread::*};
|
||||
|
||||
pub(crate) type CidMap =
|
||||
HashMap<u64, (Arc<RwLock<RawPktsQ>>, Arc<RwLock<HashSet<String>>>, EventFd)>;
|
||||
@ -65,9 +64,11 @@ pub(crate) const VSOCK_OP_CREDIT_UPDATE: u16 = 6;
|
||||
/// Vsock packet operation ID - Flow control credit request
|
||||
pub(crate) const VSOCK_OP_CREDIT_REQUEST: u16 = 7;
|
||||
|
||||
/// Vsock packet flags - `VSOCK_OP_SHUTDOWN`: Packet sender will receive no more data
|
||||
/// Vsock packet flags - `VSOCK_OP_SHUTDOWN`: Packet sender will receive no more
|
||||
/// data
|
||||
pub(crate) const VSOCK_FLAGS_SHUTDOWN_RCV: u32 = 1;
|
||||
/// Vsock packet flags - `VSOCK_OP_SHUTDOWN`: Packet sender will send no more data
|
||||
/// Vsock packet flags - `VSOCK_OP_SHUTDOWN`: Packet sender will send no more
|
||||
/// data
|
||||
pub(crate) const VSOCK_FLAGS_SHUTDOWN_SEND: u32 = 2;
|
||||
|
||||
// Queue mask to select vrings.
|
||||
@ -396,12 +397,14 @@ impl VhostUserBackend for VhostUserVsockBackend {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use tempfile::tempdir;
|
||||
use vhost_user_backend::VringT;
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
use super::*;
|
||||
|
||||
const CONN_TX_BUF_SIZE: u32 = 64 * 1024;
|
||||
const QUEUE_SIZE: usize = 1024;
|
||||
|
||||
|
||||
@ -81,11 +81,13 @@ pub(crate) struct VhostUserVsockThread {
|
||||
local_port: Wrapping<u32>,
|
||||
/// The tx buffer size
|
||||
tx_buffer_size: u32,
|
||||
/// EventFd to notify this thread for custom events. Currently used to notify
|
||||
/// this thread to process raw vsock packets sent from a sibling VM.
|
||||
/// EventFd to notify this thread for custom events. Currently used to
|
||||
/// notify this thread to process raw vsock packets sent from a sibling
|
||||
/// VM.
|
||||
pub sibling_event_fd: EventFd,
|
||||
/// Keeps track of which RX queue was processed first in the last iteration.
|
||||
/// Used to alternate between the RX queues to prevent the starvation of one by the other.
|
||||
/// Used to alternate between the RX queues to prevent the starvation of one
|
||||
/// by the other.
|
||||
last_processed: RxQueueType,
|
||||
}
|
||||
|
||||
@ -647,7 +649,8 @@ impl VhostUserVsockThread {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wrapper to process rx queue based on whether event idx is enabled or not.
|
||||
/// Wrapper to process rx queue based on whether event idx is enabled or
|
||||
/// not.
|
||||
fn process_unix_sockets(&mut self, vring: &VringRwLock, event_idx: bool) -> Result<()> {
|
||||
if event_idx {
|
||||
// To properly handle EVENT_IDX we need to keep calling
|
||||
@ -671,7 +674,8 @@ impl VhostUserVsockThread {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wrapper to process raw vsock packets queue based on whether event idx is enabled or not.
|
||||
/// Wrapper to process raw vsock packets queue based on whether event idx is
|
||||
/// enabled or not.
|
||||
pub fn process_raw_pkts(&mut self, vring: &VringRwLock, event_idx: bool) -> Result<()> {
|
||||
if event_idx {
|
||||
loop {
|
||||
@ -772,7 +776,8 @@ impl VhostUserVsockThread {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wrapper to process tx queue based on whether event idx is enabled or not.
|
||||
/// Wrapper to process tx queue based on whether event idx is enabled or
|
||||
/// not.
|
||||
pub fn process_tx(&mut self, vring_lock: &VringRwLock, event_idx: bool) -> Result<()> {
|
||||
if event_idx {
|
||||
// To properly handle EVENT_IDX we need to keep calling
|
||||
@ -813,19 +818,22 @@ impl Drop for VhostUserVsockThread {
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use crate::vhu_vsock::VsockProxyInfo;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use tempfile::tempdir;
|
||||
use vm_memory::GuestAddress;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use vsock::{VsockStream, VMADDR_CID_LOCAL};
|
||||
|
||||
use super::*;
|
||||
#[cfg(feature = "backend_vsock")]
|
||||
use crate::vhu_vsock::VsockProxyInfo;
|
||||
|
||||
const CONN_TX_BUF_SIZE: u32 = 64 * 1024;
|
||||
|
||||
impl VhostUserVsockThread {
|
||||
|
||||
@ -188,7 +188,8 @@ impl<S: AsRawFd + ReadVolatile + Write + WriteVolatile + IsHybridVsock> VsockCon
|
||||
self.stream.as_raw_fd(),
|
||||
epoll::Events::EPOLLIN | epoll::Events::EPOLLOUT,
|
||||
) {
|
||||
// TODO: let's move this logic out of this func, and handle it properly
|
||||
// TODO: let's move this logic out of this func, and handle it
|
||||
// properly
|
||||
error!("epoll_register failed: {:?}, but proceed further.", e);
|
||||
}
|
||||
};
|
||||
@ -393,17 +394,18 @@ impl<S: AsRawFd + ReadVolatile + Write + WriteVolatile + IsHybridVsock> VsockCon
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
io::{Read, Result as IoResult},
|
||||
ops::Deref,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::vhu_vsock::{VSOCK_HOST_CID, VSOCK_OP_RW, VSOCK_TYPE_STREAM};
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{Read, Result as IoResult};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
|
||||
use virtio_queue::{
|
||||
desc::split::Descriptor as SplitDescriptor, desc::RawDescriptor, mock::MockSplitQueue,
|
||||
desc::{split::Descriptor as SplitDescriptor, RawDescriptor},
|
||||
mock::MockSplitQueue,
|
||||
DescriptorChain, Queue, QueueOwnedT,
|
||||
};
|
||||
use vm_memory::{
|
||||
@ -411,6 +413,9 @@ mod tests {
|
||||
GuestMemoryMmap,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::vhu_vsock::{VSOCK_HOST_CID, VSOCK_OP_RW, VSOCK_TYPE_STREAM};
|
||||
|
||||
const CONN_TX_BUF_SIZE: u32 = 64 * 1024;
|
||||
|
||||
struct HeadParams {
|
||||
@ -534,9 +539,9 @@ mod tests {
|
||||
|
||||
// Creates a socket pair
|
||||
//
|
||||
// The read buffer of one socket is the write socket of the other (and vice versa).
|
||||
// One socket can be passed to the backend while the other can be used to fake writes
|
||||
// or to verify data that the backend wrote.
|
||||
// The read buffer of one socket is the write socket of the other (and vice
|
||||
// versa). One socket can be passed to the backend while the other can
|
||||
// be used to fake writes or to verify data that the backend wrote.
|
||||
fn pair() -> (VsockDummySocket, VsockDummySocket) {
|
||||
let buf1 = Arc::new(Mutex::new(VecDeque::new()));
|
||||
let buf2 = Arc::new(Mutex::new(VecDeque::new()));
|
||||
@ -570,7 +575,8 @@ mod tests {
|
||||
) -> std::result::Result<usize, vm_memory::VolatileMemoryError> {
|
||||
// VecDequeue has no fancy unsafe tricks that vm-memory can abstract.
|
||||
// One could do fairly efficient stuff using the moving From<Vec> imp...
|
||||
// But this is just for tests, so lets clone, convert to Vec, append, convert back and replace.
|
||||
// But this is just for tests, so lets clone, convert to Vec, append, convert
|
||||
// back and replace.
|
||||
let mut write_buffer = self.write_buffer.lock().unwrap();
|
||||
let mut vec = Vec::from(write_buffer.clone());
|
||||
let n = vec.write_volatile(buf)?;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user