1use std::cell::RefCell;
6use std::collections::BTreeMap;
7use std::collections::BTreeSet;
8use std::io;
9use std::io::Write;
10use std::mem::size_of;
11use std::rc::Rc;
12use std::result;
13use std::sync::atomic::AtomicU64;
14use std::sync::atomic::Ordering;
15use std::sync::Arc;
16use std::time::Duration;
17
18use anyhow::Context;
19use base::debug;
20use base::error;
21use base::info;
22use base::warn;
23use base::AsRawDescriptor;
24use base::Error as SysError;
25use base::Event;
26use base::RawDescriptor;
27use base::Result as SysResult;
28use base::Timer;
29use base::Tube;
30use base::TubeError;
31use base::WorkerThread;
32use cros_async::sync::RwLock as AsyncRwLock;
33use cros_async::AsyncError;
34use cros_async::AsyncTube;
35use cros_async::EventAsync;
36use cros_async::Executor;
37use cros_async::ExecutorKind;
38use cros_async::IoOptions;
39use cros_async::TimerAsync;
40use data_model::Le16;
41use data_model::Le32;
42use data_model::Le64;
43use devices::virtio::async_utils;
44use devices::virtio::copy_config;
45use devices::virtio::device_constants::block::virtio_blk_config;
46use devices::virtio::device_constants::block::virtio_blk_discard_write_zeroes;
47use devices::virtio::device_constants::block::virtio_blk_req_header;
48use devices::virtio::device_constants::block::VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP;
49use devices::virtio::device_constants::block::VIRTIO_BLK_F_BLK_SIZE;
50use devices::virtio::device_constants::block::VIRTIO_BLK_F_DISCARD;
51use devices::virtio::device_constants::block::VIRTIO_BLK_F_FLUSH;
52use devices::virtio::device_constants::block::VIRTIO_BLK_F_MQ;
53use devices::virtio::device_constants::block::VIRTIO_BLK_F_RO;
54use devices::virtio::device_constants::block::VIRTIO_BLK_F_SEG_MAX;
55use devices::virtio::device_constants::block::VIRTIO_BLK_F_WRITE_ZEROES;
56use devices::virtio::device_constants::block::VIRTIO_BLK_S_IOERR;
57use devices::virtio::device_constants::block::VIRTIO_BLK_S_OK;
58use devices::virtio::device_constants::block::VIRTIO_BLK_S_UNSUPP;
59use devices::virtio::device_constants::block::VIRTIO_BLK_T_DISCARD;
60use devices::virtio::device_constants::block::VIRTIO_BLK_T_FLUSH;
61use devices::virtio::device_constants::block::VIRTIO_BLK_T_GET_ID;
62use devices::virtio::device_constants::block::VIRTIO_BLK_T_IN;
63use devices::virtio::device_constants::block::VIRTIO_BLK_T_OUT;
64use devices::virtio::device_constants::block::VIRTIO_BLK_T_WRITE_ZEROES;
65use devices::virtio::DescriptorChain;
66use devices::virtio::DeviceType;
67use devices::virtio::Interrupt;
68use devices::virtio::Queue;
69use devices::virtio::Reader;
70use devices::virtio::VirtioDevice;
71use devices::virtio::Writer;
72use devices::PciAddress;
73use disk::AsyncDisk;
74use disk::DiskFile;
75use futures::channel::mpsc;
76use futures::channel::oneshot;
77use futures::pin_mut;
78use futures::stream::FuturesUnordered;
79use futures::stream::StreamExt;
80use futures::FutureExt;
81use remain::sorted;
82use snapshot::AnySnapshot;
83use thiserror::Error as ThisError;
84use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED;
85use vm_control::DiskControlCommand;
86use vm_control::DiskControlResult;
87use vm_memory::GuestMemory;
88use zerocopy::IntoBytes;
89
90use crate::interrupt_coalescer::InterruptCoalescer;
91use crate::sys::*;
92use crate::DiskOption;
93
94const DEFAULT_QUEUE_SIZE: u16 = 256;
95const DEFAULT_NUM_QUEUES: u16 = 16;
96
97const SECTOR_SHIFT: u8 = 9;
98const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
99
100const MAX_DISCARD_SECTORS: u32 = u32::MAX;
101const MAX_WRITE_ZEROES_SECTORS: u32 = u32::MAX;
102const MAX_DISCARD_SEG: u32 = 32;
104const MAX_WRITE_ZEROES_SEG: u32 = 32;
105const DISCARD_SECTOR_ALIGNMENT: u32 = 128;
108
109#[sorted]
110#[derive(ThisError, Debug)]
111enum ExecuteError {
112 #[error("failed to copy ID string: {0}")]
113 CopyId(io::Error),
114 #[error("failed to perform discard or write zeroes; sector={sector} num_sectors={num_sectors} flags={flags}; {ioerr:?}")]
115 DiscardWriteZeroes {
116 ioerr: Option<disk::Error>,
117 sector: u64,
118 num_sectors: u32,
119 flags: u32,
120 },
121 #[error("failed to flush: {0}")]
122 Flush(disk::Error),
123 #[error("not enough space in descriptor chain to write status")]
124 MissingStatus,
125 #[error("out of range")]
126 OutOfRange,
127 #[error("failed to read message: {0}")]
128 Read(io::Error),
129 #[error("io error reading {length} bytes from sector {sector}: {desc_error}")]
130 ReadIo {
131 length: usize,
132 sector: u64,
133 desc_error: disk::Error,
134 },
135 #[error("read only; request_type={request_type}")]
136 ReadOnly { request_type: u32 },
137 #[error("failed to recieve command message: {0}")]
138 ReceivingCommand(TubeError),
139 #[error("failed to send command response: {0}")]
140 SendingResponse(TubeError),
141 #[error("couldn't reset the timer: {0}")]
142 TimerReset(base::Error),
143 #[error("too many segments: {0} > {0}")]
144 TooManySegments(usize, usize),
145 #[error("unsupported ({0})")]
146 Unsupported(u32),
147 #[error("io error writing {length} bytes from sector {sector}: {desc_error}")]
148 WriteIo {
149 length: usize,
150 sector: u64,
151 desc_error: disk::Error,
152 },
153 #[error("failed to write request status: {0}")]
154 WriteStatus(io::Error),
155}
156
157enum LogLevel {
158 Debug,
159 Error,
160}
161
162impl ExecuteError {
163 fn status(&self) -> u8 {
164 match self {
165 ExecuteError::CopyId(_) => VIRTIO_BLK_S_IOERR,
166 ExecuteError::DiscardWriteZeroes { .. } => VIRTIO_BLK_S_IOERR,
167 ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR,
168 ExecuteError::MissingStatus => VIRTIO_BLK_S_IOERR,
169 ExecuteError::OutOfRange => VIRTIO_BLK_S_IOERR,
170 ExecuteError::Read(_) => VIRTIO_BLK_S_IOERR,
171 ExecuteError::ReadIo { .. } => VIRTIO_BLK_S_IOERR,
172 ExecuteError::ReadOnly { .. } => VIRTIO_BLK_S_IOERR,
173 ExecuteError::ReceivingCommand(_) => VIRTIO_BLK_S_IOERR,
174 ExecuteError::SendingResponse(_) => VIRTIO_BLK_S_IOERR,
175 ExecuteError::TimerReset(_) => VIRTIO_BLK_S_IOERR,
176 ExecuteError::TooManySegments(_, _) => VIRTIO_BLK_S_IOERR,
177 ExecuteError::WriteIo { .. } => VIRTIO_BLK_S_IOERR,
178 ExecuteError::WriteStatus(_) => VIRTIO_BLK_S_IOERR,
179 ExecuteError::Unsupported(_) => VIRTIO_BLK_S_UNSUPP,
180 }
181 }
182
183 fn log_level(&self) -> LogLevel {
184 match self {
185 ExecuteError::ReadIo { .. }
187 | ExecuteError::WriteIo { .. }
188 | ExecuteError::Flush { .. }
189 | ExecuteError::DiscardWriteZeroes { .. } => LogLevel::Debug,
190 _ => LogLevel::Error,
192 }
193 }
194}
195
196#[sorted]
199#[derive(ThisError, Debug)]
200enum ControlError {
201 #[error("failed to fdatasync the disk: {0}")]
202 FdatasyncDisk(disk::Error),
203 #[error("couldn't get a value from a timer for flushing: {0}")]
204 FlushTimer(AsyncError),
205}
206
207const ID_LEN: usize = 20;
209
210type BlockId = [u8; ID_LEN];
214
215struct DiskState {
217 disk_image: Box<dyn AsyncDisk>,
218 read_only: bool,
219 sparse: bool,
220 id: BlockId,
221 dontcache_read: bool,
222 dontcache_write: bool,
223 worker_shared_state: Arc<AsyncRwLock<WorkerSharedState>>,
226}
227
228struct WorkerSharedState {
230 disk_size: Arc<AtomicU64>,
231}
232
233async fn process_one_request(
234 avail_desc: &mut DescriptorChain,
235 disk_state: &AsyncRwLock<DiskState>,
236 flush_timer: &RefCell<TimerAsync<Timer>>,
237 flush_timer_armed: &RefCell<bool>,
238) -> result::Result<usize, ExecuteError> {
239 let reader = &mut avail_desc.reader;
240 let writer = &mut avail_desc.writer;
241
242 let available_bytes = writer.available_bytes();
246 let status_offset = available_bytes
247 .checked_sub(1)
248 .ok_or(ExecuteError::MissingStatus)?;
249 let mut status_writer = writer.split_at(status_offset);
250
251 let status = match BlockAsync::execute_request(
252 reader,
253 writer,
254 disk_state,
255 flush_timer,
256 flush_timer_armed,
257 )
258 .await
259 {
260 Ok(()) => VIRTIO_BLK_S_OK,
261 Err(e) => {
262 match e.log_level() {
263 LogLevel::Debug => debug!("failed executing disk request: {:#}", e),
264 LogLevel::Error => error!("failed executing disk request: {:#}", e),
265 }
266 e.status()
267 }
268 };
269
270 status_writer
271 .write_all(&[status])
272 .map_err(ExecuteError::WriteStatus)?;
273 Ok(available_bytes)
274}
275
276async fn process_one_chain(
278 queue: &RefCell<Queue>,
279 mut avail_desc: DescriptorChain,
280 disk_state: &AsyncRwLock<DiskState>,
281 flush_timer: &RefCell<TimerAsync<Timer>>,
282 flush_timer_armed: &RefCell<bool>,
283 irq_coalescer: &InterruptCoalescer,
284) {
285 let len = match process_one_request(&mut avail_desc, disk_state, flush_timer, flush_timer_armed)
286 .await
287 {
288 Ok(len) => len,
289 Err(e) => {
290 error!("block: failed to handle request: {:#}", e);
291 0
292 }
293 };
294
295 let mut queue = queue.borrow_mut();
296 queue.add_used_with_bytes_written(avail_desc, len as u32);
297 irq_coalescer.trigger_interrupt(|| {
298 queue.trigger_interrupt();
299 });
300}
301
302async fn handle_queue(
306 disk_state: Rc<AsyncRwLock<DiskState>>,
307 queue: Queue,
308 evt: EventAsync,
309 flush_timer: Rc<RefCell<TimerAsync<Timer>>>,
310 flush_timer_armed: Rc<RefCell<bool>>,
311 mut stop_rx: oneshot::Receiver<()>,
312) -> Queue {
313 let queue = RefCell::new(queue);
314 let irq_coalescer = InterruptCoalescer::new();
315 let mut background_tasks = FuturesUnordered::new();
316 let evt_future = futures::future::Either::Left(std::future::ready(Ok(0))).fuse();
317 pin_mut!(evt_future);
318 loop {
319 futures::select_biased! {
333 _ = background_tasks.next() => continue,
334 _ = irq_coalescer.active() => {
335 irq_coalescer.complete(|| {
336 queue.borrow_mut().trigger_interrupt();
337 });
338 continue;
339 }
340 _ = stop_rx => {
341 background_tasks.collect::<()>().await;
344 irq_coalescer.complete(|| {
345 queue.borrow_mut().trigger_interrupt();
346 });
347 return queue.into_inner();
348 }
349 res = evt_future => {
350 evt_future.set(futures::future::Either::Right(evt.next_val()).fuse());
351 if let Err(e) = res {
352 error!("Failed to read the next queue event: {:#}", e);
353 continue;
354 }
355 }
356 };
357 while let Some(descriptor_chain) = queue.borrow_mut().pop() {
358 background_tasks.push(process_one_chain(
359 &queue,
360 descriptor_chain,
361 &disk_state,
362 &flush_timer,
363 &flush_timer_armed,
364 &irq_coalescer,
365 ));
366 }
367 }
368}
369
370async fn handle_command_tube(
371 command_tube: &Option<AsyncTube>,
372 interrupt: &RefCell<Option<Interrupt>>,
373 disk_state: Rc<AsyncRwLock<DiskState>>,
374) -> Result<(), ExecuteError> {
375 let command_tube = match command_tube {
376 Some(c) => c,
377 None => {
378 futures::future::pending::<()>().await;
379 return Ok(());
380 }
381 };
382 loop {
383 match command_tube.next().await {
384 Ok(command) => {
385 let resp = match command {
386 DiskControlCommand::Resize { new_size } => resize(&disk_state, new_size).await,
387 };
388
389 let resp_clone = resp.clone();
390 command_tube
391 .send(resp_clone)
392 .await
393 .map_err(ExecuteError::SendingResponse)?;
394 if let DiskControlResult::Ok = resp {
395 if let Some(interrupt) = &*interrupt.borrow() {
396 interrupt.signal_config_changed();
397 }
398 }
399 }
400 Err(e) => return Err(ExecuteError::ReceivingCommand(e)),
401 }
402 }
403}
404
405async fn resize(disk_state: &AsyncRwLock<DiskState>, new_size: u64) -> DiskControlResult {
406 let disk_state = disk_state.lock().await;
409 let worker_shared_state = Arc::clone(&disk_state.worker_shared_state);
411 let worker_shared_state = worker_shared_state.lock().await;
412
413 if disk_state.read_only {
414 error!("Attempted to resize read-only block device");
415 return DiskControlResult::Err(SysError::new(libc::EROFS));
416 }
417
418 info!("Resizing block device to {} bytes", new_size);
419
420 if let Err(e) = disk_state.disk_image.set_len(new_size) {
421 error!("Resizing disk failed! {:#}", e);
422 return DiskControlResult::Err(SysError::new(libc::EIO));
423 }
424
425 if !disk_state.sparse {
427 if let Err(e) = disk_state.disk_image.allocate(0, new_size) {
428 error!("Allocating disk space after resize failed! {:#}", e);
429 return DiskControlResult::Err(SysError::new(libc::EIO));
430 }
431 }
432
433 if let Ok(new_disk_size) = disk_state.disk_image.get_len() {
434 worker_shared_state
435 .disk_size
436 .store(new_disk_size, Ordering::Release);
437 }
438 DiskControlResult::Ok
439}
440
441async fn flush_disk(
443 disk_state: Rc<AsyncRwLock<DiskState>>,
444 timer: TimerAsync<Timer>,
445 armed: Rc<RefCell<bool>>,
446) -> Result<(), ControlError> {
447 loop {
448 timer.wait().await.map_err(ControlError::FlushTimer)?;
449 if !*armed.borrow() {
450 continue;
451 }
452
453 *armed.borrow_mut() = false;
456
457 disk_state
458 .read_lock()
459 .await
460 .disk_image
461 .fdatasync()
462 .await
463 .map_err(ControlError::FdatasyncDisk)?;
464 }
465}
466
467enum WorkerCmd {
468 StartQueue {
469 index: usize,
470 queue: Queue,
471 },
472 StopQueue {
473 index: usize,
474 response_tx: oneshot::Sender<Option<Queue>>,
477 },
478 AbortQueues {
481 response_tx: oneshot::Sender<()>,
483 },
484 FlushDisk {
486 response_tx: oneshot::Sender<()>,
488 },
489}
490
491async fn run_worker(
498 ex: &Executor,
499 disk_state: &Rc<AsyncRwLock<DiskState>>,
500 control_tube: &Option<AsyncTube>,
501 mut worker_rx: mpsc::UnboundedReceiver<WorkerCmd>,
502 kill_evt: Event,
503) -> anyhow::Result<()> {
504 let timer = Timer::new().expect("Failed to create a timer");
506 let flush_timer_armed = Rc::new(RefCell::new(false));
507
508 let control_interrupt = RefCell::new(None);
510 let control = handle_command_tube(control_tube, &control_interrupt, disk_state.clone()).fuse();
511 pin_mut!(control);
512
513 let flush_timer = Rc::new(RefCell::new(
515 TimerAsync::new(
516 timer.try_clone().expect("Failed to clone flush_timer"),
518 ex,
519 )
520 .expect("Failed to create an async timer"),
521 ));
522
523 let flush_timer2 = TimerAsync::new(timer, ex).expect("Failed to create an async timer");
525 let disk_flush = flush_disk(disk_state.clone(), flush_timer2, flush_timer_armed.clone()).fuse();
526 pin_mut!(disk_flush);
527
528 let kill = async_utils::await_and_exit(ex, kill_evt).fuse();
530 pin_mut!(kill);
531
532 let mut queue_handlers = FuturesUnordered::new();
534 let mut queue_handler_stop_fns = std::collections::BTreeMap::new();
536
537 loop {
538 futures::select! {
539 _ = queue_handlers.next() => continue,
540 r = disk_flush => return r.context("failed to flush a disk"),
541 r = control => return r.context("failed to handle a control request"),
542 r = kill => return r.context("failed to wait on the kill event"),
543 worker_cmd = worker_rx.next() => {
544 match worker_cmd {
545 None => anyhow::bail!("worker control channel unexpectedly closed"),
546 Some(WorkerCmd::StartQueue{index, queue}) => {
547 if control_interrupt.borrow().is_none() {
548 *control_interrupt.borrow_mut() = Some(queue.interrupt().clone());
549 }
550
551 let (tx, rx) = oneshot::channel();
552 let kick_evt = queue.event().try_clone().expect("Failed to clone queue event");
553 let (handle_queue_future, remote_handle) = handle_queue(
554 Rc::clone(disk_state),
555 queue,
556 EventAsync::new(kick_evt, ex).expect("Failed to create async event for queue"),
557 Rc::clone(&flush_timer),
558 Rc::clone(&flush_timer_armed),
559 rx,
560 ).remote_handle();
561 let old_stop_fn = queue_handler_stop_fns.insert(index, move || {
562 tx.send(()).unwrap_or_else(|_| panic!("queue handler channel closed early"));
564 remote_handle
566 });
567
568 if let Some(stop_fn) = old_stop_fn {
571 warn!("Starting new queue handler without stopping old handler");
572 let mut fut = stop_fn().fuse();
575 loop {
576 futures::select! {
577 _ = queue_handlers.next() => continue,
578 _queue = fut => break,
579 }
580 }
581 }
582
583 queue_handlers.push(handle_queue_future);
584 }
585 Some(WorkerCmd::StopQueue{index, response_tx}) => {
586 match queue_handler_stop_fns.remove(&index) {
587 Some(stop_fn) => {
588 let mut fut = stop_fn().fuse();
596 let queue = loop {
597 futures::select! {
598 _ = queue_handlers.next() => continue,
599 queue = fut => break queue,
600 }
601 };
602
603 if queue_handlers.is_empty() {
607 *control_interrupt.borrow_mut() = None;
608 }
609
610 let _ = response_tx.send(Some(queue));
611 }
612 None => { let _ = response_tx.send(None); },
613 }
614
615 }
616 Some(WorkerCmd::AbortQueues{response_tx}) => {
617 queue_handlers.clear();
618 queue_handler_stop_fns.clear();
619
620 *control_interrupt.borrow_mut() = None;
621
622 let _ = response_tx.send(());
623 }
624 Some(WorkerCmd::FlushDisk{response_tx}) => {
625 let disk = disk_state.read_lock().await;
626 if let Err(e) = disk.disk_image.flush().await {
627 error!("failed to flush disk image: {:#}", e);
628 }
629 let _ = response_tx.send(());
630 }
631 }
632 }
633 };
634 }
635}
636
637pub struct BlockAsync {
639 boot_index: Option<usize>,
642 disk_image: Option<Box<dyn DiskFile>>,
644 disk_size: Arc<AtomicU64>,
645 avail_features: u64,
646 read_only: bool,
647 sparse: bool,
648 seg_max: u32,
649 block_size: u32,
650 id: BlockId,
651 control_tube: Option<Tube>,
652 queue_sizes: Vec<u16>,
653 pub(super) executor_kind: ExecutorKind,
654 worker_threads: BTreeMap<usize, (WorkerThread<()>, mpsc::UnboundedSender<WorkerCmd>)>,
662 shared_state: Arc<AsyncRwLock<WorkerSharedState>>,
663 worker_per_queue: bool,
665 activated_queues: BTreeSet<usize>,
669 #[cfg(windows)]
670 pub(super) io_concurrency: u32,
671 pci_address: Option<PciAddress>,
672 dontcache_read: bool,
673 dontcache_write: bool,
674}
675
676impl BlockAsync {
677 pub fn new(
679 base_features: u64,
680 disk_image: Box<dyn DiskFile>,
681 disk_option: &DiskOption,
682 control_tube: Option<Tube>,
683 queue_size: Option<u16>,
684 num_queues: Option<u16>,
685 ) -> SysResult<BlockAsync> {
686 let read_only = disk_option.read_only;
687 let sparse = disk_option.sparse;
688 let block_size = disk_option.block_size;
689 let packed_queue = disk_option.packed_queue;
690 let id = disk_option.id.unwrap_or_default();
691 let mut worker_per_queue = disk_option.multiple_workers;
692 if worker_per_queue && disk_image.try_clone().is_err() {
694 base::warn!("multiple workers requested, but not supported by disk image type");
695 worker_per_queue = false;
696 }
697 let executor_kind = disk_option.async_executor.unwrap_or_default();
698 let boot_index = disk_option.bootindex;
699 #[cfg(windows)]
700 let io_concurrency = disk_option.io_concurrency.get();
701
702 if block_size % SECTOR_SIZE as u32 != 0 {
703 error!(
704 "Block size {} is not a multiple of {}.",
705 block_size, SECTOR_SIZE,
706 );
707 return Err(SysError::new(libc::EINVAL));
708 }
709 let disk_size = disk_image.get_len()?;
710 if disk_size % block_size as u64 != 0 {
711 warn!(
712 "Disk size {} is not a multiple of block size {}; \
713 the remainder will not be visible to the guest.",
714 disk_size, block_size,
715 );
716 }
717 let num_queues = num_queues.unwrap_or(DEFAULT_NUM_QUEUES);
718 let multi_queue = match num_queues {
719 0 => panic!("Number of queues cannot be zero for a block device"),
720 1 => false,
721 _ => true,
722 };
723 let q_size = queue_size.unwrap_or(DEFAULT_QUEUE_SIZE);
724 if !q_size.is_power_of_two() {
725 error!("queue size {} is not a power of 2.", q_size);
726 return Err(SysError::new(libc::EINVAL));
727 }
728 let queue_sizes = vec![q_size; num_queues as usize];
729
730 let avail_features =
731 Self::build_avail_features(base_features, read_only, sparse, multi_queue, packed_queue);
732
733 let seg_max = get_seg_max(q_size);
734
735 let disk_size = Arc::new(AtomicU64::new(disk_size));
736 let shared_state = Arc::new(AsyncRwLock::new(WorkerSharedState {
737 disk_size: disk_size.clone(),
738 }));
739
740 let mut dontcache_read = disk_option.dontcache;
741 let mut dontcache_write = disk_option.dontcache;
742 if dontcache_write {
743 let descriptors = disk_image.as_raw_descriptors();
744 if descriptors.is_empty()
745 || !descriptors
746 .iter()
747 .all(|&fd| check_dontcache_support(fd, true ))
748 {
749 base::info!(
750 "dontcache requested, but not supported for writes by backing filesystem; falling
751 back to cached I/O"
752 );
753 dontcache_write = false;
754 }
755 }
756 if dontcache_read {
757 let descriptors = disk_image.as_raw_descriptors();
758 if descriptors.is_empty()
759 || !descriptors
760 .iter()
761 .all(|&fd| check_dontcache_support(fd, false ))
762 {
763 base::info!(
764 "dontcache requested, but not supported for reads by backing filesystem; falling
765 back to cached I/O"
766 );
767 dontcache_read = false;
768 }
769 }
770
771 Ok(BlockAsync {
772 disk_image: Some(disk_image),
773 disk_size,
774 avail_features,
775 read_only,
776 sparse,
777 seg_max,
778 block_size,
779 id,
780 queue_sizes,
781 worker_threads: BTreeMap::new(),
782 shared_state,
783 worker_per_queue,
784 control_tube,
785 executor_kind,
786 activated_queues: BTreeSet::new(),
787 boot_index,
788 #[cfg(windows)]
789 io_concurrency,
790 pci_address: disk_option.pci_address,
791 dontcache_read,
792 dontcache_write,
793 })
794 }
795
796 fn build_avail_features(
798 base_features: u64,
799 read_only: bool,
800 sparse: bool,
801 multi_queue: bool,
802 packed_queue: bool,
803 ) -> u64 {
804 let mut avail_features = base_features;
805 if read_only {
806 avail_features |= 1 << VIRTIO_BLK_F_RO;
807 } else {
808 if sparse {
809 avail_features |= 1 << VIRTIO_BLK_F_DISCARD;
810 }
811 avail_features |= 1 << VIRTIO_BLK_F_FLUSH;
812 avail_features |= 1 << VIRTIO_BLK_F_WRITE_ZEROES;
813 }
814 avail_features |= 1 << VIRTIO_BLK_F_SEG_MAX;
815 avail_features |= 1 << VIRTIO_BLK_F_BLK_SIZE;
816 if multi_queue {
817 avail_features |= 1 << VIRTIO_BLK_F_MQ;
818 }
819 if packed_queue {
820 avail_features |= 1 << VIRTIO_F_RING_PACKED;
821 }
822 avail_features
823 }
824
825 async fn execute_request(
830 reader: &mut Reader,
831 writer: &mut Writer,
832 disk_state: &AsyncRwLock<DiskState>,
833 flush_timer: &RefCell<TimerAsync<Timer>>,
834 flush_timer_armed: &RefCell<bool>,
835 ) -> result::Result<(), ExecuteError> {
836 let disk_state = disk_state.read_lock().await;
838 let worker_shared_state = disk_state.worker_shared_state.read_lock().await;
840
841 let req_header: virtio_blk_req_header = reader.read_obj().map_err(ExecuteError::Read)?;
842
843 let req_type = req_header.req_type.to_native();
844 let sector = req_header.sector.to_native();
845
846 if disk_state.read_only && req_type != VIRTIO_BLK_T_IN && req_type != VIRTIO_BLK_T_GET_ID {
847 return Err(ExecuteError::ReadOnly {
848 request_type: req_type,
849 });
850 }
851
852 fn check_range(
855 io_start: u64,
856 io_length: u64,
857 disk_size: u64,
858 ) -> result::Result<(), ExecuteError> {
859 let io_end = io_start
860 .checked_add(io_length)
861 .ok_or(ExecuteError::OutOfRange)?;
862 if io_end > disk_size {
863 Err(ExecuteError::OutOfRange)
864 } else {
865 Ok(())
866 }
867 }
868
869 let disk_size = worker_shared_state.disk_size.load(Ordering::Relaxed);
870 match req_type {
871 VIRTIO_BLK_T_IN => {
872 let data_len = writer.available_bytes();
873 if data_len == 0 {
874 return Ok(());
875 }
876 let offset = sector
877 .checked_shl(u32::from(SECTOR_SHIFT))
878 .ok_or(ExecuteError::OutOfRange)?;
879 check_range(offset, data_len as u64, disk_size)?;
880 let disk_image = &disk_state.disk_image;
881 writer
882 .write_all_from_at_fut(
883 &**disk_image,
884 data_len,
885 offset,
886 IoOptions {
887 dontcache: disk_state.dontcache_read,
888 },
889 )
890 .await
891 .map_err(|desc_error| ExecuteError::ReadIo {
892 length: data_len,
893 sector,
894 desc_error,
895 })?;
896 }
897 VIRTIO_BLK_T_OUT => {
898 let data_len = reader.available_bytes();
899 if data_len == 0 {
900 return Ok(());
901 }
902 let offset = sector
903 .checked_shl(u32::from(SECTOR_SHIFT))
904 .ok_or(ExecuteError::OutOfRange)?;
905 check_range(offset, data_len as u64, disk_size)?;
906 let disk_image = &disk_state.disk_image;
907 reader
908 .read_exact_to_at_fut(
909 &**disk_image,
910 data_len,
911 offset,
912 IoOptions {
913 dontcache: disk_state.dontcache_write,
914 },
915 )
916 .await
917 .map_err(|desc_error| ExecuteError::WriteIo {
918 length: data_len,
919 sector,
920 desc_error,
921 })?;
922
923 if !*flush_timer_armed.borrow() {
924 *flush_timer_armed.borrow_mut() = true;
925
926 let flush_delay = Duration::from_secs(60);
927 flush_timer
928 .borrow_mut()
929 .reset_oneshot(flush_delay)
930 .map_err(ExecuteError::TimerReset)?;
931 }
932 }
933 VIRTIO_BLK_T_DISCARD | VIRTIO_BLK_T_WRITE_ZEROES => {
934 if req_type == VIRTIO_BLK_T_DISCARD && !disk_state.sparse {
935 return Ok(());
937 }
938
939 let seg_count =
940 reader.available_bytes() / size_of::<virtio_blk_discard_write_zeroes>();
941 let seg_max = if req_type == VIRTIO_BLK_T_DISCARD {
942 MAX_DISCARD_SEG as usize
943 } else {
944 MAX_WRITE_ZEROES_SEG as usize
945 };
946 if seg_count > seg_max {
947 return Err(ExecuteError::TooManySegments(seg_count, seg_max));
948 }
949
950 while reader.available_bytes() >= size_of::<virtio_blk_discard_write_zeroes>() {
951 let seg: virtio_blk_discard_write_zeroes =
952 reader.read_obj().map_err(ExecuteError::Read)?;
953
954 let sector = seg.sector.to_native();
955 let num_sectors = seg.num_sectors.to_native();
956 let flags = seg.flags.to_native();
957
958 let valid_flags = if req_type == VIRTIO_BLK_T_WRITE_ZEROES {
959 VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP
960 } else {
961 0
962 };
963
964 if (flags & !valid_flags) != 0 {
965 return Err(ExecuteError::DiscardWriteZeroes {
966 ioerr: None,
967 sector,
968 num_sectors,
969 flags,
970 });
971 }
972
973 let offset = sector
974 .checked_shl(u32::from(SECTOR_SHIFT))
975 .ok_or(ExecuteError::OutOfRange)?;
976 let length = u64::from(num_sectors)
977 .checked_shl(u32::from(SECTOR_SHIFT))
978 .ok_or(ExecuteError::OutOfRange)?;
979 check_range(offset, length, disk_size)?;
980
981 if req_type == VIRTIO_BLK_T_DISCARD {
982 let _ = disk_state.disk_image.punch_hole(offset, length).await;
985 } else {
986 disk_state
987 .disk_image
988 .write_zeroes_at(offset, length)
989 .await
990 .map_err(|e| ExecuteError::DiscardWriteZeroes {
991 ioerr: Some(e),
992 sector,
993 num_sectors,
994 flags,
995 })?;
996 }
997 }
998 }
999 VIRTIO_BLK_T_FLUSH => {
1000 disk_state
1001 .disk_image
1002 .fdatasync()
1003 .await
1004 .map_err(ExecuteError::Flush)?;
1005
1006 if *flush_timer_armed.borrow() {
1007 flush_timer
1008 .borrow_mut()
1009 .clear()
1010 .map_err(ExecuteError::TimerReset)?;
1011 *flush_timer_armed.borrow_mut() = false;
1012 }
1013 }
1014 VIRTIO_BLK_T_GET_ID => {
1015 writer
1016 .write_all(&disk_state.id)
1017 .map_err(ExecuteError::CopyId)?;
1018 }
1019 t => return Err(ExecuteError::Unsupported(t)),
1020 };
1021 Ok(())
1022 }
1023
1024 fn build_config_space(
1026 disk_size: u64,
1027 seg_max: u32,
1028 block_size: u32,
1029 num_queues: u16,
1030 ) -> virtio_blk_config {
1031 virtio_blk_config {
1032 capacity: Le64::from(disk_size >> SECTOR_SHIFT),
1034 seg_max: Le32::from(seg_max),
1035 blk_size: Le32::from(block_size),
1036 num_queues: Le16::from(num_queues),
1037 max_discard_sectors: Le32::from(MAX_DISCARD_SECTORS),
1038 discard_sector_alignment: Le32::from(DISCARD_SECTOR_ALIGNMENT),
1039 max_write_zeroes_sectors: Le32::from(MAX_WRITE_ZEROES_SECTORS),
1040 write_zeroes_may_unmap: 1,
1041 max_discard_seg: Le32::from(MAX_DISCARD_SEG),
1042 max_write_zeroes_seg: Le32::from(MAX_WRITE_ZEROES_SEG),
1043 ..Default::default()
1044 }
1045 }
1046
1047 #[allow(clippy::map_entry)]
1050 fn start_worker(
1051 &mut self,
1052 idx: usize,
1053 ) -> anyhow::Result<&(WorkerThread<()>, mpsc::UnboundedSender<WorkerCmd>)> {
1054 let key = if self.worker_per_queue { idx } else { 0 };
1055 if self.worker_threads.contains_key(&key) {
1056 return Ok(self.worker_threads.get(&key).unwrap());
1057 }
1058
1059 let ex = self.create_executor();
1060 let control_tube = self.control_tube.take();
1061 let dontcache_read = self.dontcache_read;
1062 let dontcache_write = self.dontcache_write;
1063 let disk_image = if self.worker_per_queue {
1064 self.disk_image
1065 .as_ref()
1066 .context("Failed to ref a disk image")?
1067 .try_clone()
1068 .context("Failed to clone a disk image")?
1069 } else {
1070 self.disk_image
1071 .take()
1072 .context("Failed to take a disk image")?
1073 };
1074 let read_only = self.read_only;
1075 let sparse = self.sparse;
1076 let id = self.id;
1077 let worker_shared_state = self.shared_state.clone();
1078
1079 let (worker_tx, worker_rx) = mpsc::unbounded();
1080 let worker_thread = WorkerThread::start("virtio_blk", move |kill_evt| {
1081 let async_control =
1082 control_tube.map(|c| AsyncTube::new(&ex, c).expect("failed to create async tube"));
1083
1084 let async_image = match disk_image.to_async_disk(&ex) {
1085 Ok(d) => d,
1086 Err(e) => panic!("Failed to create async disk {e:#}"),
1087 };
1088
1089 let disk_state = Rc::new(AsyncRwLock::new(DiskState {
1090 disk_image: async_image,
1091 read_only,
1092 sparse,
1093 id,
1094 dontcache_read,
1095 dontcache_write,
1096 worker_shared_state,
1097 }));
1098
1099 if let Err(err_string) = ex
1100 .run_until(async {
1101 let r = run_worker(&ex, &disk_state, &async_control, worker_rx, kill_evt).await;
1102 if let Err(e) = disk_state.lock().await.disk_image.flush().await {
1104 error!("failed to flush disk image when stopping worker: {e:?}");
1105 }
1106 r
1107 })
1108 .expect("run_until failed")
1109 {
1110 error!("{:#}", err_string);
1111 }
1112 });
1113 match self.worker_threads.entry(key) {
1114 std::collections::btree_map::Entry::Occupied(_) => unreachable!(),
1115 std::collections::btree_map::Entry::Vacant(e) => {
1116 Ok(e.insert((worker_thread, worker_tx)))
1117 }
1118 }
1119 }
1120
1121 pub fn start_queue(
1122 &mut self,
1123 idx: usize,
1124 queue: Queue,
1125 _mem: GuestMemory,
1126 ) -> anyhow::Result<()> {
1127 let (_, worker_tx) = self.start_worker(idx)?;
1128 worker_tx
1129 .unbounded_send(WorkerCmd::StartQueue { index: idx, queue })
1130 .expect("worker channel closed early");
1131 self.activated_queues.insert(idx);
1132 Ok(())
1133 }
1134
1135 pub fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue> {
1136 let (_, worker_tx) = self
1139 .worker_threads
1140 .get(if self.worker_per_queue { &idx } else { &0 })
1141 .context("worker not found")?;
1142 let (response_tx, response_rx) = oneshot::channel();
1143 worker_tx
1144 .unbounded_send(WorkerCmd::StopQueue {
1145 index: idx,
1146 response_tx,
1147 })
1148 .expect("worker channel closed early");
1149 let queue = cros_async::block_on(async {
1150 response_rx
1151 .await
1152 .expect("response_rx closed early")
1153 .context("queue not found")
1154 })?;
1155 self.activated_queues.remove(&idx);
1156 Ok(queue)
1157 }
1158}
1159
1160impl VirtioDevice for BlockAsync {
1161 fn keep_rds(&self) -> Vec<RawDescriptor> {
1162 let mut keep_rds = Vec::new();
1163
1164 if let Some(disk_image) = &self.disk_image {
1165 keep_rds.extend(disk_image.as_raw_descriptors());
1166 }
1167
1168 if let Some(control_tube) = &self.control_tube {
1169 keep_rds.push(control_tube.as_raw_descriptor());
1170 }
1171
1172 keep_rds
1173 }
1174
1175 fn features(&self) -> u64 {
1176 self.avail_features
1177 }
1178
1179 fn device_type(&self) -> DeviceType {
1180 DeviceType::Block
1181 }
1182
1183 fn queue_max_sizes(&self) -> &[u16] {
1184 &self.queue_sizes
1185 }
1186
1187 fn read_config(&self, offset: u64, data: &mut [u8]) {
1188 let config_space = {
1189 let disk_size = self.disk_size.load(Ordering::Acquire);
1190 Self::build_config_space(
1191 disk_size,
1192 self.seg_max,
1193 self.block_size,
1194 self.queue_sizes.len() as u16,
1195 )
1196 };
1197 copy_config(data, 0, config_space.as_bytes(), offset);
1198 }
1199
1200 fn activate(
1201 &mut self,
1202 mem: GuestMemory,
1203 _interrupt: Interrupt,
1204 queues: BTreeMap<usize, Queue>,
1205 ) -> anyhow::Result<()> {
1206 for (i, q) in queues {
1207 self.start_queue(i, q, mem.clone())?;
1208 }
1209 Ok(())
1210 }
1211
1212 fn reset(&mut self) -> anyhow::Result<()> {
1213 for (_, (_, worker_tx)) in self.worker_threads.iter_mut() {
1214 let (response_tx, response_rx) = oneshot::channel();
1215 worker_tx
1216 .unbounded_send(WorkerCmd::AbortQueues { response_tx })
1217 .expect("worker channel closed early");
1218 cros_async::block_on(async { response_rx.await.expect("response_rx closed early") });
1219 }
1220 self.activated_queues.clear();
1221 Ok(())
1222 }
1223
1224 fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
1225 let mut queues = BTreeMap::new();
1227 for index in self.activated_queues.clone() {
1228 queues.insert(index, self.stop_queue(index)?);
1229 }
1230 if queues.is_empty() {
1231 return Ok(None); }
1233 if let Some((_, (_, worker_tx))) = self.worker_threads.iter().next() {
1234 let (response_tx, response_rx) = oneshot::channel();
1235 worker_tx
1236 .unbounded_send(WorkerCmd::FlushDisk { response_tx })
1237 .expect("worker channel closed early");
1238 cros_async::block_on(async { response_rx.await.expect("response_rx closed early") });
1239 }
1240 Ok(Some(queues))
1241 }
1242
1243 fn virtio_wake(
1244 &mut self,
1245 queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
1246 ) -> anyhow::Result<()> {
1247 if let Some((mem, _interrupt, queues)) = queues_state {
1248 for (i, q) in queues {
1249 self.start_queue(i, q, mem.clone())?
1250 }
1251 }
1252 Ok(())
1253 }
1254
1255 fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
1256 AnySnapshot::to_any(())
1259 }
1260
1261 fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
1262 let () = AnySnapshot::from_any(data)?;
1263 Ok(())
1264 }
1265
1266 fn pci_address(&self) -> Option<PciAddress> {
1267 self.pci_address
1268 }
1269
1270 fn bootorder_fw_cfg(&self, pci_slot: u8) -> Option<(Vec<u8>, usize)> {
1271 self.boot_index
1272 .map(|s| (format!("scsi@{pci_slot}/disk@0,0").as_bytes().to_vec(), s))
1273 }
1274}
1275
1276#[cfg(test)]
1277mod tests {
1278 use std::fs::File;
1279 use std::mem::size_of_val;
1280 use std::sync::atomic::AtomicU64;
1281
1282 use data_model::Le32;
1283 use data_model::Le64;
1284 #[cfg(any(target_os = "android", target_os = "linux"))]
1285 use devices::suspendable_virtio_tests;
1286 use devices::virtio::base_features;
1287 use devices::virtio::create_descriptor_chain;
1288 use devices::virtio::DescriptorType;
1289 use devices::virtio::QueueConfig;
1290 use disk::SingleFileDisk;
1291 use hypervisor::ProtectionType;
1292 use tempfile::tempfile;
1293 use tempfile::TempDir;
1294 use vm_memory::GuestAddress;
1295
1296 use super::*;
1297
1298 #[test]
1299 fn read_size() {
1300 let f = tempfile().unwrap();
1301 f.set_len(0x1000).unwrap();
1302
1303 let features = base_features(ProtectionType::Unprotected);
1304 let disk_option = DiskOption::default();
1305 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1306 let mut num_sectors = [0u8; 4];
1307 b.read_config(0, &mut num_sectors);
1308 assert_eq!([0x08, 0x00, 0x00, 0x00], num_sectors);
1310 let mut msw_sectors = [0u8; 4];
1311 b.read_config(4, &mut msw_sectors);
1312 assert_eq!([0x00, 0x00, 0x00, 0x00], msw_sectors);
1314 }
1315
1316 #[test]
1317 fn read_block_size() {
1318 let f = tempfile().unwrap();
1319 f.set_len(0x1000).unwrap();
1320
1321 let features = base_features(ProtectionType::Unprotected);
1322 let disk_option = DiskOption {
1323 block_size: 4096,
1324 sparse: false,
1325 ..Default::default()
1326 };
1327 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1328 let mut blk_size = [0u8; 4];
1329 b.read_config(20, &mut blk_size);
1330 assert_eq!([0x00, 0x10, 0x00, 0x00], blk_size);
1332 }
1333
1334 #[test]
1335 fn read_features() {
1336 let tempdir = TempDir::new().unwrap();
1337 let mut path = tempdir.path().to_owned();
1338 path.push("disk_image");
1339
1340 const DEVICE_FEATURE_BITS: u64 = 0xffffff;
1343
1344 {
1346 let f = File::create(&path).unwrap();
1347 let features = base_features(ProtectionType::Unprotected);
1348 let disk_option = DiskOption::default();
1349 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1350 assert_eq!(0x7244, b.features() & DEVICE_FEATURE_BITS);
1354 }
1355
1356 {
1358 let f = File::create(&path).unwrap();
1359 let features = base_features(ProtectionType::Unprotected);
1360 let disk_option = DiskOption {
1361 sparse: false,
1362 ..Default::default()
1363 };
1364 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1365 assert_eq!(0x5244, b.features() & DEVICE_FEATURE_BITS);
1368 }
1369
1370 {
1372 let f = File::create(&path).unwrap();
1373 let features = base_features(ProtectionType::Unprotected);
1374 let disk_option = DiskOption {
1375 read_only: true,
1376 ..Default::default()
1377 };
1378 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1379 assert_eq!(0x1064, b.features() & DEVICE_FEATURE_BITS);
1382 }
1383 }
1384
1385 #[test]
1386 fn check_pci_adress_configurability() {
1387 let f = tempfile().unwrap();
1388
1389 let features = base_features(ProtectionType::Unprotected);
1390 let disk_option = DiskOption {
1391 pci_address: Some(PciAddress {
1392 bus: 0,
1393 dev: 1,
1394 func: 1,
1395 }),
1396 ..Default::default()
1397 };
1398 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1399
1400 assert_eq!(b.pci_address(), disk_option.pci_address);
1401 }
1402
1403 #[test]
1404 fn check_runtime_blk_queue_configurability() {
1405 let tempdir = TempDir::new().unwrap();
1406 let mut path = tempdir.path().to_owned();
1407 path.push("disk_image");
1408 let features = base_features(ProtectionType::Unprotected);
1409
1410 let f = File::create(&path).unwrap();
1412 let disk_option = DiskOption::default();
1413 let b = BlockAsync::new(features, Box::new(f), &disk_option, None, None, None).unwrap();
1414 assert_eq!(
1415 [DEFAULT_QUEUE_SIZE; DEFAULT_NUM_QUEUES as usize],
1416 b.queue_max_sizes()
1417 );
1418
1419 let f = File::create(&path).unwrap();
1421 let disk_option = DiskOption::default();
1422 let b = BlockAsync::new(
1423 features,
1424 Box::new(f),
1425 &disk_option,
1426 None,
1427 Some(128),
1428 Some(1),
1429 )
1430 .unwrap();
1431 assert_eq!([128; 1], b.queue_max_sizes());
1432 assert_eq!(0, b.features() & (1 << VIRTIO_BLK_F_MQ) as u64);
1434 }
1435
1436 #[test]
1437 fn read_last_sector() {
1438 let ex = Executor::new().expect("creating an executor failed");
1439
1440 let f = tempfile().unwrap();
1441 let disk_size = 0x1000;
1442 f.set_len(disk_size).unwrap();
1443 let af = SingleFileDisk::new(f, &ex).expect("Failed to create SFD");
1444
1445 let mem = Rc::new(
1446 GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
1447 .expect("Creating guest memory failed."),
1448 );
1449
1450 let req_hdr = virtio_blk_req_header {
1451 req_type: Le32::from(VIRTIO_BLK_T_IN),
1452 reserved: Le32::from(0),
1453 sector: Le64::from(7), };
1455 mem.write_obj_at_addr(req_hdr, GuestAddress(0x1000))
1456 .expect("writing req failed");
1457
1458 let mut avail_desc = create_descriptor_chain(
1459 &mem,
1460 GuestAddress(0x100), GuestAddress(0x1000), vec![
1463 (DescriptorType::Readable, size_of_val(&req_hdr) as u32),
1465 (DescriptorType::Writable, 512),
1467 (DescriptorType::Writable, 1),
1469 ],
1470 0,
1471 )
1472 .expect("create_descriptor_chain failed");
1473
1474 let timer = Timer::new().expect("Failed to create a timer");
1475 let flush_timer = Rc::new(RefCell::new(
1476 TimerAsync::new(timer, &ex).expect("Failed to create an async timer"),
1477 ));
1478 let flush_timer_armed = Rc::new(RefCell::new(false));
1479
1480 let disk_state = Rc::new(AsyncRwLock::new(DiskState {
1481 disk_image: Box::new(af),
1482 read_only: false,
1483 sparse: true,
1484 id: Default::default(),
1485 dontcache_read: false,
1486 dontcache_write: false,
1487 worker_shared_state: Arc::new(AsyncRwLock::new(WorkerSharedState {
1488 disk_size: Arc::new(AtomicU64::new(disk_size)),
1489 })),
1490 }));
1491
1492 let fut = process_one_request(
1493 &mut avail_desc,
1494 &disk_state,
1495 &flush_timer,
1496 &flush_timer_armed,
1497 );
1498
1499 ex.run_until(fut)
1500 .expect("running executor failed")
1501 .expect("execute failed");
1502
1503 let status_offset = GuestAddress((0x1000 + size_of_val(&req_hdr) + 512) as u64);
1504 let status = mem.read_obj_from_addr::<u8>(status_offset).unwrap();
1505 assert_eq!(status, VIRTIO_BLK_S_OK);
1506 }
1507
1508 #[test]
1509 fn read_beyond_last_sector() {
1510 let f = tempfile().unwrap();
1511 let disk_size = 0x1000;
1512 f.set_len(disk_size).unwrap();
1513 let mem = Rc::new(
1514 GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
1515 .expect("Creating guest memory failed."),
1516 );
1517
1518 let req_hdr = virtio_blk_req_header {
1519 req_type: Le32::from(VIRTIO_BLK_T_IN),
1520 reserved: Le32::from(0),
1521 sector: Le64::from(7), };
1523 mem.write_obj_at_addr(req_hdr, GuestAddress(0x1000))
1524 .expect("writing req failed");
1525
1526 let mut avail_desc = create_descriptor_chain(
1527 &mem,
1528 GuestAddress(0x100), GuestAddress(0x1000), vec![
1531 (DescriptorType::Readable, size_of_val(&req_hdr) as u32),
1533 (DescriptorType::Writable, 512 * 2),
1535 (DescriptorType::Writable, 1),
1537 ],
1538 0,
1539 )
1540 .expect("create_descriptor_chain failed");
1541
1542 let ex = Executor::new().expect("creating an executor failed");
1543
1544 let af = SingleFileDisk::new(f, &ex).expect("Failed to create SFD");
1545 let timer = Timer::new().expect("Failed to create a timer");
1546 let flush_timer = Rc::new(RefCell::new(
1547 TimerAsync::new(timer, &ex).expect("Failed to create an async timer"),
1548 ));
1549 let flush_timer_armed = Rc::new(RefCell::new(false));
1550 let disk_state = Rc::new(AsyncRwLock::new(DiskState {
1551 disk_image: Box::new(af),
1552 read_only: false,
1553 sparse: true,
1554 id: Default::default(),
1555 dontcache_read: false,
1556 dontcache_write: false,
1557 worker_shared_state: Arc::new(AsyncRwLock::new(WorkerSharedState {
1558 disk_size: Arc::new(AtomicU64::new(disk_size)),
1559 })),
1560 }));
1561
1562 let fut = process_one_request(
1563 &mut avail_desc,
1564 &disk_state,
1565 &flush_timer,
1566 &flush_timer_armed,
1567 );
1568
1569 ex.run_until(fut)
1570 .expect("running executor failed")
1571 .expect("execute failed");
1572
1573 let status_offset = GuestAddress((0x1000 + size_of_val(&req_hdr) + 512 * 2) as u64);
1574 let status = mem.read_obj_from_addr::<u8>(status_offset).unwrap();
1575 assert_eq!(status, VIRTIO_BLK_S_IOERR);
1576 }
1577
1578 #[test]
1579 fn get_id() {
1580 let ex = Executor::new().expect("creating an executor failed");
1581
1582 let f = tempfile().unwrap();
1583 let disk_size = 0x1000;
1584 f.set_len(disk_size).unwrap();
1585
1586 let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
1587 .expect("Creating guest memory failed.");
1588
1589 let req_hdr = virtio_blk_req_header {
1590 req_type: Le32::from(VIRTIO_BLK_T_GET_ID),
1591 reserved: Le32::from(0),
1592 sector: Le64::from(0),
1593 };
1594 mem.write_obj_at_addr(req_hdr, GuestAddress(0x1000))
1595 .expect("writing req failed");
1596
1597 let mut avail_desc = create_descriptor_chain(
1598 &mem,
1599 GuestAddress(0x100), GuestAddress(0x1000), vec![
1602 (DescriptorType::Readable, size_of_val(&req_hdr) as u32),
1604 (DescriptorType::Writable, 20),
1606 (DescriptorType::Writable, 1),
1608 ],
1609 0,
1610 )
1611 .expect("create_descriptor_chain failed");
1612
1613 let af = SingleFileDisk::new(f, &ex).expect("Failed to create SFD");
1614 let timer = Timer::new().expect("Failed to create a timer");
1615 let flush_timer = Rc::new(RefCell::new(
1616 TimerAsync::new(timer, &ex).expect("Failed to create an async timer"),
1617 ));
1618 let flush_timer_armed = Rc::new(RefCell::new(false));
1619
1620 let id = b"a20-byteserialnumber";
1621
1622 let disk_state = Rc::new(AsyncRwLock::new(DiskState {
1623 disk_image: Box::new(af),
1624 read_only: false,
1625 sparse: true,
1626 id: *id,
1627 dontcache_read: false,
1628 dontcache_write: false,
1629 worker_shared_state: Arc::new(AsyncRwLock::new(WorkerSharedState {
1630 disk_size: Arc::new(AtomicU64::new(disk_size)),
1631 })),
1632 }));
1633
1634 let fut = process_one_request(
1635 &mut avail_desc,
1636 &disk_state,
1637 &flush_timer,
1638 &flush_timer_armed,
1639 );
1640
1641 ex.run_until(fut)
1642 .expect("running executor failed")
1643 .expect("execute failed");
1644
1645 let status_offset = GuestAddress((0x1000 + size_of_val(&req_hdr) + 512) as u64);
1646 let status = mem.read_obj_from_addr::<u8>(status_offset).unwrap();
1647 assert_eq!(status, VIRTIO_BLK_S_OK);
1648
1649 let id_offset = GuestAddress(0x1000 + size_of_val(&req_hdr) as u64);
1650 let returned_id = mem.read_obj_from_addr::<[u8; 20]>(id_offset).unwrap();
1651 assert_eq!(returned_id, *id);
1652 }
1653
1654 #[test]
1655 fn reset_and_reactivate_single_worker() {
1656 reset_and_reactivate(false, None);
1657 }
1658
1659 #[test]
1660 fn reset_and_reactivate_multiple_workers() {
1661 reset_and_reactivate(true, None);
1662 }
1663
1664 #[test]
1665 #[cfg(windows)]
1666 fn reset_and_reactivate_overrlapped_io() {
1667 reset_and_reactivate(
1668 false,
1669 Some(
1670 cros_async::sys::windows::ExecutorKindSys::Overlapped { concurrency: None }.into(),
1671 ),
1672 );
1673 }
1674
1675 fn reset_and_reactivate(
1676 enables_multiple_workers: bool,
1677 async_executor: Option<cros_async::ExecutorKind>,
1678 ) {
1679 let f = tempfile::NamedTempFile::new().unwrap();
1681 f.as_file().set_len(0x1000).unwrap();
1682 let path: tempfile::TempPath = f.into_temp_path();
1685
1686 let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
1688 .expect("Creating guest memory failed.");
1689
1690 let (_control_tube, control_tube_device) = Tube::pair().unwrap();
1694
1695 let features = base_features(ProtectionType::Unprotected);
1697 let id = b"Block serial number\0";
1698 let disk_option = DiskOption {
1699 path: path.to_path_buf(),
1700 read_only: true,
1701 id: Some(*id),
1702 sparse: false,
1703 multiple_workers: enables_multiple_workers,
1704 async_executor,
1705 ..Default::default()
1706 };
1707 let disk_image = disk_option.open().unwrap();
1708 let mut b = BlockAsync::new(
1709 features,
1710 disk_image,
1711 &disk_option,
1712 Some(control_tube_device),
1713 None,
1714 None,
1715 )
1716 .unwrap();
1717
1718 let interrupt = Interrupt::new_for_test();
1719
1720 let mut q0 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1722 q0.set_ready(true);
1723 let q0 = q0
1724 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1725 .expect("QueueConfig::activate");
1726
1727 let mut q1 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1728 q1.set_ready(true);
1729 let q1 = q1
1730 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1731 .expect("QueueConfig::activate");
1732
1733 b.activate(mem.clone(), interrupt, BTreeMap::from([(0, q0), (1, q1)]))
1734 .expect("activate should succeed");
1735 if !enables_multiple_workers {
1737 assert!(
1738 b.disk_image.is_none(),
1739 "BlockAsync should not have a disk image"
1740 );
1741 }
1742 assert!(
1743 b.control_tube.is_none(),
1744 "BlockAsync should not have a control tube"
1745 );
1746 assert_eq!(
1747 b.worker_threads.len(),
1748 if enables_multiple_workers { 2 } else { 1 }
1749 );
1750
1751 assert!(b.reset().is_ok(), "reset should succeed");
1753 if !enables_multiple_workers {
1754 assert!(
1755 b.disk_image.is_none(),
1756 "BlockAsync should not have a disk image"
1757 );
1758 }
1759 assert!(
1760 b.control_tube.is_none(),
1761 "BlockAsync should not have a control tube"
1762 );
1763 assert_eq!(
1764 b.worker_threads.len(),
1765 if enables_multiple_workers { 2 } else { 1 }
1766 );
1767 assert_eq!(b.id, *b"Block serial number\0");
1768
1769 let interrupt = Interrupt::new_for_test();
1771 let mut q0 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1772 q0.set_ready(true);
1773 let q0 = q0
1774 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1775 .expect("QueueConfig::activate");
1776
1777 let mut q1 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1778 q1.set_ready(true);
1779 let q1 = q1
1780 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1781 .expect("QueueConfig::activate");
1782
1783 b.activate(mem, interrupt, BTreeMap::from([(0, q0), (1, q1)]))
1784 .expect("re-activate should succeed");
1785 }
1786
1787 #[test]
1788 fn resize_with_single_worker() {
1789 resize(false);
1790 }
1791
1792 #[test]
1793 fn resize_with_multiple_workers() {
1794 resize(true);
1796 }
1797
1798 fn resize(enables_multiple_workers: bool) {
1799 let original_size = 0x1000;
1801 let resized_size = 0x2000;
1802
1803 let f = tempfile().unwrap();
1805 f.set_len(original_size).unwrap();
1806 let disk_image: Box<dyn DiskFile> = Box::new(f);
1807 assert_eq!(disk_image.get_len().unwrap(), original_size);
1808
1809 let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
1811 .expect("Creating guest memory failed.");
1812
1813 let (control_tube, control_tube_device) = Tube::pair().unwrap();
1815
1816 let features = base_features(ProtectionType::Unprotected);
1818 let disk_option = DiskOption {
1819 multiple_workers: enables_multiple_workers,
1820 ..Default::default()
1821 };
1822 let mut b = BlockAsync::new(
1823 features,
1824 disk_image.try_clone().unwrap(),
1825 &disk_option,
1826 Some(control_tube_device),
1827 None,
1828 None,
1829 )
1830 .unwrap();
1831
1832 let interrupt = Interrupt::new_for_test();
1833
1834 let mut q0 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1836 q0.set_ready(true);
1837 let q0 = q0
1838 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1839 .expect("QueueConfig::activate");
1840
1841 let mut q1 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1842 q1.set_ready(true);
1843 let q1 = q1
1844 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1845 .expect("QueueConfig::activate");
1846
1847 b.activate(mem, interrupt.clone(), BTreeMap::from([(0, q0), (1, q1)]))
1848 .expect("activate should succeed");
1849
1850 assert_eq!(
1852 b.disk_size.load(Ordering::Acquire),
1853 original_size,
1854 "disk_size should be the original size first"
1855 );
1856 let mut capacity = [0u8; 8];
1857 b.read_config(0, &mut capacity);
1858 assert_eq!(
1859 capacity,
1860 [0x8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
1862 "read_config should read the original capacity first"
1863 );
1864
1865 control_tube
1867 .send(&DiskControlCommand::Resize {
1868 new_size: resized_size,
1869 })
1870 .unwrap();
1871 assert_eq!(
1872 control_tube.recv::<DiskControlResult>().unwrap(),
1873 DiskControlResult::Ok,
1874 "resize command should succeed"
1875 );
1876 assert_eq!(
1877 b.disk_size.load(Ordering::Acquire),
1878 resized_size,
1879 "disk_size should be resized to the new size"
1880 );
1881 assert_eq!(
1882 disk_image.get_len().unwrap(),
1883 resized_size,
1884 "underlying disk image should be resized to the new size"
1885 );
1886 let mut capacity = [0u8; 8];
1887 b.read_config(0, &mut capacity);
1888 assert_eq!(
1889 capacity,
1890 [0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
1892 "read_config should read the resized capacity"
1893 );
1894 interrupt
1896 .get_interrupt_evt()
1897 .wait()
1898 .expect("interrupt should be signaled");
1899
1900 assert_eq!(
1901 interrupt.read_interrupt_status(),
1902 devices::virtio::INTERRUPT_STATUS_CONFIG_CHANGED as u8,
1903 "INTERRUPT_STATUS_CONFIG_CHANGED should be signaled"
1904 );
1905 }
1906
1907 #[test]
1908 fn run_worker_threads() {
1909 let f = tempfile().unwrap();
1911 f.set_len(0x1000).unwrap();
1912 let disk_image: Box<dyn DiskFile> = Box::new(f);
1913
1914 let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
1916 .expect("Creating guest memory failed.");
1917
1918 let features = base_features(ProtectionType::Unprotected);
1920 let disk_option = DiskOption::default();
1921 let mut b = BlockAsync::new(
1922 features,
1923 disk_image.try_clone().unwrap(),
1924 &disk_option,
1925 None,
1926 None,
1927 None,
1928 )
1929 .unwrap();
1930
1931 let interrupt = Interrupt::new_for_test();
1933 let mut q0 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1934 q0.set_ready(true);
1935 let q0 = q0
1936 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1937 .expect("QueueConfig::activate");
1938
1939 let mut q1 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1940 q1.set_ready(true);
1941 let q1 = q1
1942 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1943 .expect("QueueConfig::activate");
1944
1945 b.activate(mem.clone(), interrupt, BTreeMap::from([(0, q0), (1, q1)]))
1946 .expect("activate should succeed");
1947
1948 assert_eq!(b.worker_threads.len(), 1, "1 threads should be spawned.");
1949 drop(b);
1950
1951 let features = base_features(ProtectionType::Unprotected);
1953 let disk_option = DiskOption {
1954 read_only: true,
1955 sparse: false,
1956 multiple_workers: true,
1957 ..DiskOption::default()
1958 };
1959 let mut b = BlockAsync::new(features, disk_image, &disk_option, None, None, None).unwrap();
1960
1961 let interrupt = Interrupt::new_for_test();
1963 let mut q0 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1964 q0.set_ready(true);
1965 let q0 = q0
1966 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1967 .expect("QueueConfig::activate");
1968
1969 let mut q1 = QueueConfig::new(DEFAULT_QUEUE_SIZE, 0);
1970 q1.set_ready(true);
1971 let q1 = q1
1972 .activate(&mem, Event::new().unwrap(), interrupt.clone())
1973 .expect("QueueConfig::activate");
1974
1975 b.activate(mem, interrupt, BTreeMap::from([(0, q0), (1, q1)]))
1976 .expect("activate should succeed");
1977
1978 assert_eq!(b.worker_threads.len(), 2, "2 threads should be spawned.");
1979 }
1980
1981 #[cfg(any(target_os = "android", target_os = "linux"))]
1982 struct BlockContext {}
1983
1984 #[cfg(any(target_os = "android", target_os = "linux"))]
1985 fn modify_device(_block_context: &mut BlockContext, b: &mut BlockAsync) {
1986 b.avail_features = !b.avail_features;
1987 }
1988
1989 #[cfg(any(target_os = "android", target_os = "linux"))]
1990 fn create_device() -> (BlockContext, BlockAsync) {
1991 let f = tempfile().unwrap();
1993 f.set_len(0x1000).unwrap();
1994 let disk_image: Box<dyn DiskFile> = Box::new(f);
1995
1996 let features = base_features(ProtectionType::Unprotected);
1998 let id = b"Block serial number\0";
1999 let disk_option = DiskOption {
2000 read_only: true,
2001 id: Some(*id),
2002 sparse: false,
2003 multiple_workers: true,
2004 ..Default::default()
2005 };
2006 (
2007 BlockContext {},
2008 BlockAsync::new(
2009 features,
2010 disk_image.try_clone().unwrap(),
2011 &disk_option,
2012 None,
2013 None,
2014 None,
2015 )
2016 .unwrap(),
2017 )
2018 }
2019
2020 #[cfg(any(target_os = "android", target_os = "linux"))]
2021 suspendable_virtio_tests!(asyncblock, create_device, 2, modify_device);
2022}