(
&mut self,
mem: &vm_memory::GuestMemoryMmap<B>,
disk_nsectors: u64,
disk_image: &mut dyn AsyncIo,
serial: &[u8],
disable_sector0_writes: bool,
| 235 | } |
| 236 | |
| 237 | pub fn execute_async<B: Bitmap + 'static>( |
| 238 | &mut self, |
| 239 | mem: &vm_memory::GuestMemoryMmap<B>, |
| 240 | disk_nsectors: u64, |
| 241 | disk_image: &mut dyn AsyncIo, |
| 242 | serial: &[u8], |
| 243 | disable_sector0_writes: bool, |
| 244 | user_data: u64, |
| 245 | ) -> Result<ExecuteAsync, ExecuteError> { |
| 246 | let sector = self.sector; |
| 247 | let request_type = self.request_type; |
| 248 | let offset = (sector << SECTOR_SHIFT) as libc::off_t; |
| 249 | let alignment = disk_image.alignment(); |
| 250 | |
| 251 | self.check_data_bounds(disk_nsectors)?; |
| 252 | |
| 253 | let mut iovecs: SmallVec<[libc::iovec; DEFAULT_DESCRIPTOR_VEC_SIZE]> = |
| 254 | SmallVec::with_capacity(self.data_descriptors.len()); |
| 255 | for &(data_addr, data_len) in &self.data_descriptors { |
| 256 | let _: u32 = data_len; // compiler-checked documentation |
| 257 | const _: () = assert!( |
| 258 | core::mem::size_of::<u32>() <= core::mem::size_of::<usize>(), |
| 259 | "unsupported platform" |
| 260 | ); |
| 261 | if data_len == 0 { |
| 262 | continue; |
| 263 | } |
| 264 | let data_len = data_len as usize; |
| 265 | |
| 266 | let origin_ptr = mem |
| 267 | .get_slice(data_addr, data_len) |
| 268 | .map_err(ExecuteError::GetHostAddress)?; |
| 269 | assert!(origin_ptr.len() >= data_len); |
| 270 | let origin_ptr = origin_ptr.ptr_guard_mut(); |
| 271 | |
| 272 | // O_DIRECT requires buffer addresses to be aligned to the |
| 273 | // backend device's logical block size. In case it's not properly |
| 274 | // aligned, an intermediate buffer is created with the correct |
| 275 | // alignment, and a copy from/to the origin buffer is performed, |
| 276 | // depending on the type of operation. |
| 277 | let iov_base = if (origin_ptr.as_ptr() as u64).is_multiple_of(alignment) { |
| 278 | origin_ptr.as_ptr().cast() |
| 279 | } else { |
| 280 | let mut aligned_op = AlignedOperation::new(data_addr, data_len, alignment as usize) |
| 281 | .map_err(ExecuteError::TemporaryBufferAllocation)?; |
| 282 | |
| 283 | // We need to perform the copy beforehand in case we're writing |
| 284 | // data out. |
| 285 | if request_type == RequestType::Out { |
| 286 | mem.read_slice(aligned_op.as_bytes_mut(), data_addr) |
| 287 | .map_err(ExecuteError::Read)?; |
| 288 | } |
| 289 | |
| 290 | let aligned_ptr = aligned_op.as_mut_ptr(); |
| 291 | self.aligned_operations.push(aligned_op); |
| 292 | |
| 293 | aligned_ptr.cast() |
| 294 | }; |
no test coverage detected