1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Testing virtio-block.
6
7 #![cfg(any(target_os = "android", target_os = "linux"))]
8
9 use std::time;
10
11 use fixture::utils::create_vu_block_config;
12 use fixture::utils::prepare_disk_img;
13 use fixture::utils::DEFAULT_BLOCK_SIZE;
14 use fixture::vhost_user::CmdType;
15 use fixture::vhost_user::VhostUserBackend;
16 use fixture::vm::Config as VmConfig;
17 use fixture::vm::TestVm;
18 use tempfile::NamedTempFile;
19
20 /// Tests virtio-blk device is mountable.
21 // TODO(b/243127498): Add tests for write and sync operations.
22 #[test]
test_mount_block()23 fn test_mount_block() {
24 let config = VmConfig::new();
25 mount_block(config);
26 }
27
28 #[test]
test_mount_block_disable_sandbox()29 fn test_mount_block_disable_sandbox() {
30 let config = VmConfig::new().disable_sandbox();
31 mount_block(config);
32 }
33
mount_block(config: VmConfig)34 fn mount_block(config: VmConfig) {
35 let disk = prepare_disk_img();
36 let disk_path = disk.path().to_str().unwrap();
37 println!("disk={disk_path}");
38
39 let config = config.extra_args(vec!["--block".to_string(), format!("{},ro", disk_path)]);
40 let mut vm = TestVm::new(config).unwrap();
41 assert_eq!(
42 vm.exec_in_guest("mount -t ext4 /dev/vdb /mnt && echo 42")
43 .unwrap()
44 .stdout
45 .trim(),
46 "42"
47 );
48 }
49
50 /// Tests `crosvm disk resize` works.
51 #[test]
test_resize()52 fn test_resize() {
53 let config = VmConfig::new();
54 resize(config);
55 }
56
57 #[test]
test_resize_disable_sandbox()58 fn test_resize_disable_sandbox() {
59 let config = VmConfig::new().disable_sandbox();
60 resize(config);
61 }
62
resize(config: VmConfig)63 fn resize(config: VmConfig) {
64 let disk = prepare_disk_img();
65 let disk_path = disk.path().to_str().unwrap().to_string();
66 println!("disk={disk_path}");
67
68 let config = config.extra_args(vec!["--block".to_string(), disk_path]);
69 let mut vm = TestVm::new(config).unwrap();
70
71 // Check the initial block device size.
72 assert_eq!(
73 vm.exec_in_guest("blockdev --getsize64 /dev/vdb")
74 .unwrap()
75 .stdout
76 .trim()
77 .parse::<u64>()
78 .unwrap(),
79 DEFAULT_BLOCK_SIZE
80 );
81
82 let new_size = DEFAULT_BLOCK_SIZE * 2;
83
84 // The index of the disk to resize.
85 let disk_index = 1;
86
87 vm.disk(vec![
88 "resize".to_string(),
89 disk_index.to_string(),
90 new_size.to_string(),
91 ])
92 .expect("Disk resizing command failed");
93
94 // Allow block device size to be updated within 500ms
95 let now = time::Instant::now();
96
97 while now.elapsed() <= time::Duration::from_millis(500) {
98 if vm
99 .exec_in_guest("blockdev --getsize64 /dev/vdb")
100 .unwrap()
101 .stdout
102 .trim()
103 .parse::<u64>()
104 .unwrap()
105 == new_size
106 {
107 return;
108 }
109 }
110 // Check the new block device size.
111 assert_eq!(
112 vm.exec_in_guest("blockdev --getsize64 /dev/vdb")
113 .unwrap()
114 .stdout
115 .trim()
116 .parse::<u64>()
117 .unwrap(),
118 new_size
119 );
120 }
121
run_vhost_user_test(cmd_type: CmdType, config: VmConfig)122 fn run_vhost_user_test(cmd_type: CmdType, config: VmConfig) {
123 let socket = NamedTempFile::new().unwrap();
124 let disk = prepare_disk_img();
125
126 let vu_config = create_vu_block_config(cmd_type, socket.path(), disk.path());
127 let _vu_device = VhostUserBackend::new(vu_config).unwrap();
128
129 let config = config.with_vhost_user("block", socket.path());
130 let mut vm = TestVm::new(config).unwrap();
131 assert_eq!(
132 vm.exec_in_guest("mount -t ext4 /dev/vdb /mnt && echo 42")
133 .unwrap()
134 .stdout
135 .trim(),
136 "42"
137 );
138 }
139
140 /// Tests vhost-user block device with `crosvm device`.
141 #[test]
vhost_user_mount()142 fn vhost_user_mount() {
143 let config = VmConfig::new();
144 run_vhost_user_test(CmdType::Device, config);
145 }
146
147 /// Tests vhost-user block device with `crosvm devices` (not `device`).
148 #[test]
vhost_user_mount_with_devices()149 fn vhost_user_mount_with_devices() {
150 let config = VmConfig::new();
151 run_vhost_user_test(CmdType::Devices, config);
152 }
153
154 /// Tests vhost-user block device with `crosvm device`.
155 #[test]
vhost_user_mount_disable_sandbox()156 fn vhost_user_mount_disable_sandbox() {
157 let config = VmConfig::new().disable_sandbox();
158 run_vhost_user_test(CmdType::Device, config);
159 }
160
161 /// Tests vhost-user block device with `crosvm devices` (not `device`).
162 #[test]
vhost_user_mount_with_devices_disable_sandbox()163 fn vhost_user_mount_with_devices_disable_sandbox() {
164 let config = VmConfig::new().disable_sandbox();
165 run_vhost_user_test(CmdType::Devices, config);
166 }
167