diff --git a/src/transport/file_volatile_slice.rs b/src/transport/file_volatile_slice.rs
index c0ab4bd..e0386e6 100644
@@ -4,9 +4,10 @@
//! Helper structures to work around limitations of the `vm-memory` crate.
//!
-//! The vm-memory v0.6.0 has added support of `Bitmap` to track dirty pages, which makes the rust
-//! compiler fail to compile our code. So introduce [FileVolatileSlice] to mask out the
-//! `BitmapSlice` generic type parameter.
+//! The vm-memory v0.6.0 introduced support of dirty page tracking by using `Bitmap`, which adds a
+//! generic type parameters to several APIs. That's a breaking change and makes the rust compiler
+//! fail to compile our code. So introduce [FileVolatileSlice] to mask out the `BitmapSlice`
+//! generic type parameter.
//!
//! Dirty page tracking is handled at higher level in `IoBuffers`.
@@ -47,7 +48,12 @@ impl fmt::Display for Error {
impl error::Error for Error {}
-/// An adapter structure to mask out the `vm_memory::BitmapSlice` generic parameter.
+/// An adapter structure to work around limitations of the `vm-memory` crate.
+///
+/// It solves the compilation failure by masking out the
+/// [`vm_memory::BitmapSlice`](https://docs.rs/vm-memory/latest/vm_memory/bitmap/trait.BitmapSlice.html)
+/// generic type parameter of
+/// [`vm_memory::VolatileSlice`](https://docs.rs/vm-memory/latest/vm_memory/volatile_memory/struct.VolatileSlice.html)
#[derive(Clone, Copy, Debug)]
pub struct FileVolatileSlice<'a> {
addr: *mut u8,
@@ -55,14 +61,38 @@ pub struct FileVolatileSlice<'a> {
phantom: PhantomData<&'a u8>,
}
-/// Safe because the field `FileVolatileSlice::addr` is used as data buffer.
+// Safe because the field `FileVolatileSlice::addr` is used as data buffer.
unsafe impl<'a> Sync for FileVolatileSlice<'a> {}
impl<'a> FileVolatileSlice<'a> {
/// Create a new instance of [`FileVolatileSlice`] from a raw pointer.
///
/// # Safety
- /// This function is the same as `VolatileSlice::new()`.
+ /// To use this safely, the caller must guarantee that the memory at addr is size bytes long
+ /// and is available for the duration of the lifetime of the new [FileVolatileSlice].
+ /// The caller must also guarantee that all other users of the given chunk of memory are using
+ /// volatile accesses.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use fuse_backend_rs::transport::FileVolatileSlice;
+ /// # use vm_memory::bytes::Bytes;
+ /// # use std::sync::atomic::Ordering;
+ /// let mut buffer = [0u8; 1024];
+ /// let s = unsafe { FileVolatileSlice::new(buffer.as_mut_ptr(), buffer.len()) };
+ ///
+ /// {
+ /// let o: u32 = s.load(0x10, Ordering::Acquire).unwrap();
+ /// assert_eq!(o, 0);
+ /// s.store(1u8, 0x10, Ordering::Release).unwrap();
+ ///
+ /// let s2 = s.as_volatile_slice();
+ /// let s3 = FileVolatileSlice::new_from_volatile_slice(&s2);
+ /// assert_eq!(s3.len(), 1024);
+ /// }
+ ///
+ /// assert_eq!(buffer[0x10], 1);
+ /// ```
pub unsafe fn new(addr: *mut u8, size: usize) -> Self {
Self {
addr,
@@ -71,35 +101,36 @@ impl<'a> FileVolatileSlice<'a> {
}
}
- /// Create a new [`FileVolatileSlice`] from [`VolatileSlice`] and strip off the [`BitmapSlice`]
- /// generic type parameter.
+ /// Create a new [`FileVolatileSlice`] from [`VolatileSlice`](https://docs.rs/vm-memory/latest/vm_memory/volatile_memory/struct.VolatileSlice.html)
+ /// and strip off the [`BitmapSlice`](https://docs.rs/vm-memory/latest/vm_memory/bitmap/trait.BitmapSlice.html) generic type parameter.
///
- /// The caller needs to dirty page tracking for the data buffer.
+ /// The caller needs to handle dirty page tracking for the data buffer.
pub fn new_from_volatile_slice<S: BitmapSlice>(s: &VolatileSlice<'a, S>) -> Self {
unsafe { Self::new(s.as_ptr(), s.len()) }
}
- /// Create a new instance of [`VolatileSlice`] without dirty page tracking.
+ /// Create a [`vm_memory::VolatileSlice`](https://docs.rs/vm-memory/latest/vm_memory/volatile_memory/struct.VolatileSlice.html)
+ /// from [FileVolatileSlice] without dirty page tracking.
pub fn as_volatile_slice(&self) -> VolatileSlice<'_, ()> {
unsafe { VolatileSlice::new(self.as_ptr(), self.len()) }
}
- /// Returns a pointer to the beginning of the slice.
+ /// Return a pointer to the start of the slice.
pub fn as_ptr(&self) -> *mut u8 {
self.addr
}
- /// Gets the size of this slice.
+ /// Get the size of the slice.
pub fn len(&self) -> usize {
self.size
}
- /// Checks if the slice is empty.
+ /// Check if the slice is empty.
pub fn is_empty(&self) -> bool {
self.size == 0
}
- /// Returns a subslice of this FileVolatileSlice starting at `offset`.
+ /// Return a subslice of this [FileVolatileSlice] starting at `offset`.
pub fn offset(&self, count: usize) -> Result<Self, Error> {
let new_addr = (self.addr as usize)
.checked_add(count)
@@ -141,12 +172,7 @@ impl<'a> Bytes<usize> for FileVolatileSlice<'a> {
VolatileSlice::read_from(&self.as_volatile_slice(), addr, src, count)
}
- fn read_exact_from<F>(
- &self,
- addr: usize,
- src: &mut F,
- count: usize,
- ) -> Result<(), Self::E>
+ fn read_exact_from<F>(&self, addr: usize, src: &mut F, count: usize) -> Result<(), Self::E>
where
F: Read,
{
@@ -167,12 +193,7 @@ impl<'a> Bytes<usize> for FileVolatileSlice<'a> {
VolatileSlice::write_all_to(&self.as_volatile_slice(), addr, dst, count)
}
- fn store<T: AtomicAccess>(
- &self,
- val: T,
- addr: usize,
- order: Ordering,
- ) -> Result<(), Self::E> {
+ fn store<T: AtomicAccess>(&self, val: T, addr: usize, order: Ordering) -> Result<(), Self::E> {
VolatileSlice::store(&self.as_volatile_slice(), val, addr, order)
}
@@ -193,10 +214,13 @@ mod tests {
let o: u32 = s.load(0x10, Ordering::Acquire).unwrap();
assert_eq!(o, 0);
s.store(1u8, 0x10, Ordering::Release).unwrap();
- assert_eq!(buffer[0x10], 1);
let s2 = s.as_volatile_slice();
let s3 = FileVolatileSlice::new_from_volatile_slice(&s2);
assert_eq!(s3.len(), 1024);
+
+ assert!(s3.offset(2048).is_err());
+
+ assert_eq!(buffer[0x10], 1);
}
-}
\ No newline at end of file
+}