(&mut self)
| 214 | } |
| 215 | |
| 216 | fn process_queue_submit(&mut self) -> Result<()> { |
| 217 | let queue = &mut self.queue; |
| 218 | let queue_size = queue.size(); |
| 219 | let mut batch_requests = Vec::new(); |
| 220 | let mut batch_inflight_requests = Vec::new(); |
| 221 | let mut processed = 0; |
| 222 | |
| 223 | loop { |
| 224 | // Cap a single drain at the virtqueue size. A compliant driver won't submit more that |
| 225 | // queue_size, but a buggy or malicious one can keep adding as the VMM is reading. |
| 226 | if processed >= queue_size { |
| 227 | break; |
| 228 | } |
| 229 | processed += 1; |
| 230 | let mut desc_chain = match queue |
| 231 | .iter(self.mem.memory()) |
| 232 | .map_err(Error::QueueIterator)? |
| 233 | .next() |
| 234 | { |
| 235 | Some(c) => c, |
| 236 | None => break, |
| 237 | }; |
| 238 | |
| 239 | let head = desc_chain.head_index(); |
| 240 | if Self::is_head_in_flight(&self.inflight_requests, &batch_inflight_requests, head) { |
| 241 | warn!("Guest reused virtio-blk head_index {head} while the chain was used"); |
| 242 | return Err(Error::QueueDuplicatedHeadIndex); |
| 243 | } |
| 244 | |
| 245 | let mut request = Request::parse(&mut desc_chain, self.access_platform.as_deref()) |
| 246 | .map_err(Error::RequestParsing)?; |
| 247 | |
| 248 | // For virtio spec compliance |
| 249 | // "A device MUST set the status byte to VIRTIO_BLK_S_IOERR for a write request |
| 250 | // if the VIRTIO_BLK_F_RO feature if offered, and MUST NOT write any data." |
| 251 | // Also, if sector 0 writes are disabled, treat writes to sector 0 as read-only as well. |
| 252 | if let Err(e) = |
| 253 | Self::check_request(self.acked_features, &request, self.disable_sector0_writes) |
| 254 | { |
| 255 | warn!("Request check failed: {request:x?} {e:?}"); |
| 256 | desc_chain |
| 257 | .memory() |
| 258 | .write_obj(VIRTIO_BLK_S_IOERR, request.status_addr()) |
| 259 | .map_err(Error::RequestStatus)?; |
| 260 | |
| 261 | // If no asynchronous operation has been submitted, we can |
| 262 | // simply return the used descriptor. |
| 263 | queue |
| 264 | .add_used(desc_chain.memory(), desc_chain.head_index(), 1) |
| 265 | .map_err(Error::QueueAddUsed)?; |
| 266 | queue |
| 267 | .enable_notification(self.mem.memory().deref()) |
| 268 | .map_err(Error::QueueEnableNotification)?; |
| 269 | continue; |
| 270 | } |
| 271 | |
| 272 | if let Some(rate_limiter) = &mut self.rate_limiter { |
| 273 | // If limiter.consume() fails it means there is no more TokenType::Ops |
no test coverage detected