2
2
//
3
3
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4
4
5
- //! vm-memory 0.6.0 added Bitmap support, which caused some interfaces
6
- //! to not compile with the extra BitmapSlice generic parameter. So added
7
- //! a FileVolatileSlice which is used for volatile access. And mask out
8
- //! BitmapSlice so that FileSystem interfaces don't have to pass BitmapSlice
9
- //! generic parameters.
10
- //! Dirty page tracking is handled in IoBuffers.
5
+ //! Helper structures to work around limitations of the `vm-memory` crate.
6
+ //!
7
+ //! The vm-memory v0.6.0 introduced support of dirty page tracking by using `Bitmap`, which adds a
8
+ //! generic type parameters to several APIs. That's a breaking change and makes the rust compiler
9
+ //! fail to compile our code. So introduce [FileVolatileSlice] to mask out the `BitmapSlice`
10
+ //! generic type parameter.
11
+ //!
12
+ //! Dirty page tracking is handled at higher level in `IoBuffers`.
13
+
11
14
use std:: io:: { Read , Write } ;
12
15
use std:: marker:: PhantomData ;
13
16
use std:: sync:: atomic:: Ordering ;
14
- use std:: { error, fmt, result } ;
17
+ use std:: { error, fmt} ;
15
18
16
19
use vm_memory:: {
17
20
bitmap:: BitmapSlice , volatile_memory:: Error as VError , AtomicAccess , Bytes , VolatileSlice ,
18
21
} ;
19
22
20
- /// `FileVolatileSlice` related errors.
23
+ /// [ `FileVolatileSlice`] related errors.
21
24
#[ allow( missing_docs) ]
22
25
#[ derive( Debug ) ]
23
26
pub enum Error {
@@ -45,24 +48,51 @@ impl fmt::Display for Error {
45
48
46
49
impl error:: Error for Error { }
47
50
48
- /// Result of volatile memory operations.
49
- pub type Result < T > = result:: Result < T , Error > ;
50
-
51
- /// A adapter in order to mask the BitmapSlice generic parameter.
51
+ /// An adapter structure to work around limitations of the `vm-memory` crate.
52
+ ///
53
+ /// It solves the compilation failure by masking out the
54
+ /// [`vm_memory::BitmapSlice`](https://docs.rs/vm-memory/latest/vm_memory/bitmap/trait.BitmapSlice.html)
55
+ /// generic type parameter of
56
+ /// [`vm_memory::VolatileSlice`](https://docs.rs/vm-memory/latest/vm_memory/volatile_memory/struct.VolatileSlice.html)
52
57
#[ derive( Clone , Copy , Debug ) ]
53
58
pub struct FileVolatileSlice < ' a > {
54
59
addr : * mut u8 ,
55
60
size : usize ,
56
61
phantom : PhantomData < & ' a u8 > ,
57
62
}
58
63
64
+ // Safe because the field `FileVolatileSlice::addr` is used as data buffer.
59
65
unsafe impl < ' a > Sync for FileVolatileSlice < ' a > { }
60
66
61
67
impl < ' a > FileVolatileSlice < ' a > {
62
- /// Create a new instance
68
+ /// Create a new instance of [`FileVolatileSlice`] from a raw pointer.
63
69
///
64
70
/// # Safety
65
- /// This function is the same as VolatileSlice::new.
71
+ /// To use this safely, the caller must guarantee that the memory at addr is size bytes long
72
+ /// and is available for the duration of the lifetime of the new [FileVolatileSlice].
73
+ /// The caller must also guarantee that all other users of the given chunk of memory are using
74
+ /// volatile accesses.
75
+ ///
76
+ /// ### Example
77
+ /// ```rust
78
+ /// # use fuse_backend_rs::transport::FileVolatileSlice;
79
+ /// # use vm_memory::bytes::Bytes;
80
+ /// # use std::sync::atomic::Ordering;
81
+ /// let mut buffer = [0u8; 1024];
82
+ /// let s = unsafe { FileVolatileSlice::new(buffer.as_mut_ptr(), buffer.len()) };
83
+ ///
84
+ /// {
85
+ /// let o: u32 = s.load(0x10, Ordering::Acquire).unwrap();
86
+ /// assert_eq!(o, 0);
87
+ /// s.store(1u8, 0x10, Ordering::Release).unwrap();
88
+ ///
89
+ /// let s2 = s.as_volatile_slice();
90
+ /// let s3 = FileVolatileSlice::new_from_volatile_slice(&s2);
91
+ /// assert_eq!(s3.len(), 1024);
92
+ /// }
93
+ ///
94
+ /// assert_eq!(buffer[0x10], 1);
95
+ /// ```
66
96
pub unsafe fn new ( addr : * mut u8 , size : usize ) -> Self {
67
97
Self {
68
98
addr,
@@ -71,34 +101,37 @@ impl<'a> FileVolatileSlice<'a> {
71
101
}
72
102
}
73
103
74
- /// Create a new FileVolatileSlice from VolatileSlice, but don't have bitmap.
75
- /// The caller needs to ensure that dirty pages are marked.
104
+ /// Create a new [`FileVolatileSlice`] from [`VolatileSlice`](https://docs.rs/vm-memory/latest/vm_memory/volatile_memory/struct.VolatileSlice.html)
105
+ /// and strip off the [`BitmapSlice`](https://docs.rs/vm-memory/latest/vm_memory/bitmap/trait.BitmapSlice.html) generic type parameter.
106
+ ///
107
+ /// The caller needs to handle dirty page tracking for the data buffer.
76
108
pub fn new_from_volatile_slice < S : BitmapSlice > ( s : & VolatileSlice < ' a , S > ) -> Self {
77
109
unsafe { Self :: new ( s. as_ptr ( ) , s. len ( ) ) }
78
110
}
79
111
80
- /// Create a new VolatileSlice
112
+ /// Create a [`vm_memory::VolatileSlice`](https://docs.rs/vm-memory/latest/vm_memory/volatile_memory/struct.VolatileSlice.html)
113
+ /// from [FileVolatileSlice] without dirty page tracking.
81
114
pub fn as_volatile_slice ( & self ) -> VolatileSlice < ' _ , ( ) > {
82
115
unsafe { VolatileSlice :: new ( self . as_ptr ( ) , self . len ( ) ) }
83
116
}
84
117
85
- /// Returns a pointer to the beginning of the slice.
118
+ /// Return a pointer to the start of the slice.
86
119
pub fn as_ptr ( & self ) -> * mut u8 {
87
120
self . addr
88
121
}
89
122
90
- /// Gets the size of this slice.
123
+ /// Get the size of the slice.
91
124
pub fn len ( & self ) -> usize {
92
125
self . size
93
126
}
94
127
95
- /// Checks if the slice is empty.
128
+ /// Check if the slice is empty.
96
129
pub fn is_empty ( & self ) -> bool {
97
130
self . size == 0
98
131
}
99
132
100
- /// Returns a subslice of this FileVolatileSlice starting at `offset`.
101
- pub fn offset ( & self , count : usize ) -> Result < Self > {
133
+ /// Return a subslice of this [ FileVolatileSlice] starting at `offset`.
134
+ pub fn offset ( & self , count : usize ) -> Result < Self , Error > {
102
135
let new_addr = ( self . addr as usize )
103
136
. checked_add ( count)
104
137
. ok_or ( Error :: Overflow {
@@ -116,65 +149,78 @@ impl<'a> FileVolatileSlice<'a> {
116
149
impl < ' a > Bytes < usize > for FileVolatileSlice < ' a > {
117
150
type E = VError ;
118
151
119
- fn write ( & self , buf : & [ u8 ] , addr : usize ) -> result :: Result < usize , Self :: E > {
152
+ fn write ( & self , buf : & [ u8 ] , addr : usize ) -> Result < usize , Self :: E > {
120
153
VolatileSlice :: write ( & self . as_volatile_slice ( ) , buf, addr)
121
154
}
122
155
123
- fn read ( & self , buf : & mut [ u8 ] , addr : usize ) -> result :: Result < usize , Self :: E > {
156
+ fn read ( & self , buf : & mut [ u8 ] , addr : usize ) -> Result < usize , Self :: E > {
124
157
VolatileSlice :: read ( & self . as_volatile_slice ( ) , buf, addr)
125
158
}
126
159
127
- fn write_slice ( & self , buf : & [ u8 ] , addr : usize ) -> result :: Result < ( ) , Self :: E > {
160
+ fn write_slice ( & self , buf : & [ u8 ] , addr : usize ) -> Result < ( ) , Self :: E > {
128
161
VolatileSlice :: write_slice ( & self . as_volatile_slice ( ) , buf, addr)
129
162
}
130
163
131
- fn read_slice ( & self , buf : & mut [ u8 ] , addr : usize ) -> result :: Result < ( ) , Self :: E > {
164
+ fn read_slice ( & self , buf : & mut [ u8 ] , addr : usize ) -> Result < ( ) , Self :: E > {
132
165
VolatileSlice :: write_slice ( & self . as_volatile_slice ( ) , buf, addr)
133
166
}
134
167
135
- fn read_from < F > ( & self , addr : usize , src : & mut F , count : usize ) -> result :: Result < usize , Self :: E >
168
+ fn read_from < F > ( & self , addr : usize , src : & mut F , count : usize ) -> Result < usize , Self :: E >
136
169
where
137
170
F : Read ,
138
171
{
139
172
VolatileSlice :: read_from ( & self . as_volatile_slice ( ) , addr, src, count)
140
173
}
141
174
142
- fn read_exact_from < F > (
143
- & self ,
144
- addr : usize ,
145
- src : & mut F ,
146
- count : usize ,
147
- ) -> result:: Result < ( ) , Self :: E >
175
+ fn read_exact_from < F > ( & self , addr : usize , src : & mut F , count : usize ) -> Result < ( ) , Self :: E >
148
176
where
149
177
F : Read ,
150
178
{
151
179
VolatileSlice :: read_exact_from ( & self . as_volatile_slice ( ) , addr, src, count)
152
180
}
153
181
154
- fn write_to < F > ( & self , addr : usize , dst : & mut F , count : usize ) -> result :: Result < usize , Self :: E >
182
+ fn write_to < F > ( & self , addr : usize , dst : & mut F , count : usize ) -> Result < usize , Self :: E >
155
183
where
156
184
F : Write ,
157
185
{
158
186
VolatileSlice :: write_to ( & self . as_volatile_slice ( ) , addr, dst, count)
159
187
}
160
188
161
- fn write_all_to < F > ( & self , addr : usize , dst : & mut F , count : usize ) -> result :: Result < ( ) , Self :: E >
189
+ fn write_all_to < F > ( & self , addr : usize , dst : & mut F , count : usize ) -> Result < ( ) , Self :: E >
162
190
where
163
191
F : Write ,
164
192
{
165
193
VolatileSlice :: write_all_to ( & self . as_volatile_slice ( ) , addr, dst, count)
166
194
}
167
195
168
- fn store < T : AtomicAccess > (
169
- & self ,
170
- val : T ,
171
- addr : usize ,
172
- order : Ordering ,
173
- ) -> result:: Result < ( ) , Self :: E > {
196
+ fn store < T : AtomicAccess > ( & self , val : T , addr : usize , order : Ordering ) -> Result < ( ) , Self :: E > {
174
197
VolatileSlice :: store ( & self . as_volatile_slice ( ) , val, addr, order)
175
198
}
176
199
177
- fn load < T : AtomicAccess > ( & self , addr : usize , order : Ordering ) -> result :: Result < T , Self :: E > {
200
+ fn load < T : AtomicAccess > ( & self , addr : usize , order : Ordering ) -> Result < T , Self :: E > {
178
201
VolatileSlice :: load ( & self . as_volatile_slice ( ) , addr, order)
179
202
}
180
203
}
204
+
205
+ #[ cfg( test) ]
206
+ mod tests {
207
+ use super :: * ;
208
+
209
+ #[ test]
210
+ fn test_new_file_volatile_slice ( ) {
211
+ let mut buffer = [ 0u8 ; 1024 ] ;
212
+ let s = unsafe { FileVolatileSlice :: new ( buffer. as_mut_ptr ( ) , buffer. len ( ) ) } ;
213
+
214
+ let o: u32 = s. load ( 0x10 , Ordering :: Acquire ) . unwrap ( ) ;
215
+ assert_eq ! ( o, 0 ) ;
216
+ s. store ( 1u8 , 0x10 , Ordering :: Release ) . unwrap ( ) ;
217
+
218
+ let s2 = s. as_volatile_slice ( ) ;
219
+ let s3 = FileVolatileSlice :: new_from_volatile_slice ( & s2) ;
220
+ assert_eq ! ( s3. len( ) , 1024 ) ;
221
+
222
+ assert ! ( s3. offset( 2048 ) . is_err( ) ) ;
223
+
224
+ assert_eq ! ( buffer[ 0x10 ] , 1 ) ;
225
+ }
226
+ }
0 commit comments