| 252 | } |
| 253 | |
| 254 | fn submit_batch_requests(&mut self, batch_request: &[BatchRequest]) -> AsyncIoResult<()> { |
| 255 | let (submitter, mut sq, _) = self.io_uring.split(); |
| 256 | let mut needs_submit = false; |
| 257 | let mut sync_completions: Vec<(u64, i32)> = Vec::new(); |
| 258 | |
| 259 | for req in batch_request { |
| 260 | match req.request_type { |
| 261 | RequestType::In => { |
| 262 | let total_len: usize = req.iovecs.iter().map(|v| v.iov_len).sum(); |
| 263 | |
| 264 | if let Some(host_offset) = Self::resolve_read( |
| 265 | &self.metadata, |
| 266 | &self.data_file, |
| 267 | &self.backing_file, |
| 268 | req.offset as u64, |
| 269 | &req.iovecs, |
| 270 | total_len, |
| 271 | self.alignment, |
| 272 | self.cluster_size, |
| 273 | &*self.decoder, |
| 274 | )? { |
| 275 | let fd = self.data_file.as_raw_fd(); |
| 276 | // SAFETY: fd is valid and iovecs point to valid guest memory. |
| 277 | unsafe { |
| 278 | sq.push( |
| 279 | &opcode::Readv::new( |
| 280 | types::Fd(fd), |
| 281 | req.iovecs.as_ptr(), |
| 282 | req.iovecs.len() as u32, |
| 283 | ) |
| 284 | .offset(host_offset) |
| 285 | .build() |
| 286 | .user_data(req.user_data), |
| 287 | ) |
| 288 | .map_err(|_| { |
| 289 | AsyncIoError::ReadVectored(io::Error::other( |
| 290 | "Submission queue is full", |
| 291 | )) |
| 292 | })?; |
| 293 | } |
| 294 | needs_submit = true; |
| 295 | } else { |
| 296 | sync_completions.push((req.user_data, total_len as i32)); |
| 297 | } |
| 298 | } |
| 299 | RequestType::Out => { |
| 300 | let total_len: usize = req.iovecs.iter().map(|v| v.iov_len).sum(); |
| 301 | Self::cow_write_sync( |
| 302 | req.offset as u64, |
| 303 | &req.iovecs, |
| 304 | &self.metadata, |
| 305 | &self.data_file, |
| 306 | &self.backing_file, |
| 307 | self.alignment, |
| 308 | self.cluster_size, |
| 309 | )?; |
| 310 | sync_completions.push((req.user_data, total_len as i32)); |
| 311 | } |