Write iovec data cluster-by-cluster with COW from backing file.
(
address: u64,
iovecs: &[libc::iovec],
metadata: &QcowMetadata,
data_file: &QcowRawFile,
backing_file: &Option<Arc<dyn BackingRead>>,
alignment: usize,
| 475 | |
| 476 | /// Write iovec data cluster-by-cluster with COW from backing file. |
| 477 | fn cow_write_sync( |
| 478 | address: u64, |
| 479 | iovecs: &[libc::iovec], |
| 480 | metadata: &QcowMetadata, |
| 481 | data_file: &QcowRawFile, |
| 482 | backing_file: &Option<Arc<dyn BackingRead>>, |
| 483 | alignment: usize, |
| 484 | cluster_size: u64, |
| 485 | ) -> AsyncIoResult<()> { |
| 486 | let total_len: usize = iovecs.iter().map(|v| v.iov_len).sum(); |
| 487 | let mut buf_offset = 0usize; |
| 488 | |
| 489 | while buf_offset < total_len { |
| 490 | let curr_addr = address + buf_offset as u64; |
| 491 | let intra_offset = curr_addr & (cluster_size - 1); |
| 492 | let remaining_in_cluster = (cluster_size - intra_offset) as usize; |
| 493 | let count = min(total_len - buf_offset, remaining_in_cluster); |
| 494 | |
| 495 | let backing_data = if let Some(backing) = backing_file |
| 496 | .as_ref() |
| 497 | .filter(|_| intra_offset != 0 || count < cluster_size as usize) |
| 498 | { |
| 499 | let cluster_begin = curr_addr - intra_offset; |
| 500 | let mut data = vec![0u8; cluster_size as usize]; |
| 501 | backing |
| 502 | .read_at(cluster_begin, &mut data) |
| 503 | .map_err(AsyncIoError::WriteVectored)?; |
| 504 | Some(data) |
| 505 | } else { |
| 506 | None |
| 507 | }; |
| 508 | |
| 509 | let mapping = metadata |
| 510 | .map_cluster_for_write(curr_addr, backing_data) |
| 511 | .map_err(AsyncIoError::WriteVectored)?; |
| 512 | |
| 513 | match mapping { |
| 514 | ClusterWriteMapping::Allocated { |
| 515 | offset: host_offset, |
| 516 | } => { |
| 517 | if alignment > 0 { |
| 518 | // O_DIRECT, gather directly into aligned buffer. |
| 519 | let mut abuf = AlignedBuf::new(count, alignment) |
| 520 | .map_err(AsyncIoError::WriteVectored)?; |
| 521 | // SAFETY: iovecs point to valid guest memory buffers |
| 522 | unsafe { |
| 523 | gather_from_iovecs_into(iovecs, buf_offset, abuf.as_mut_slice(count)); |
| 524 | } |
| 525 | aligned_pwrite( |
| 526 | data_file.as_raw_fd(), |
| 527 | abuf.as_slice(count), |
| 528 | host_offset, |
| 529 | alignment, |
| 530 | ) |
| 531 | .map_err(AsyncIoError::WriteVectored)?; |
| 532 | } else { |
| 533 | // No O_DIRECT, plain buffer is fine. |
| 534 | let mut buf = vec![0u8; count]; |
nothing calls this directly
no test coverage detected