storage_stress_test_utils/
fvm.rs1use fidl::endpoints::DiscoverableProtocolMarker;
6use fidl_fuchsia_io as fio;
7
8use fs_management::filesystem::{
9 DirBasedBlockConnector, Filesystem, ServingMultiVolumeFilesystem, ServingVolume,
10};
11use fs_management::{self, Fvm};
12use ramdevice_client::{RamdiskClient, RamdiskClientBuilder};
13pub use storage_isolated_driver_manager::Guid;
14use storage_isolated_driver_manager::create_random_guid;
15use zx::{Rights, Vmo};
16
17async fn create_ramdisk(vmo: &Vmo, ramdisk_block_size: u64) -> RamdiskClient {
18 let duplicated_handle = vmo.as_handle_ref().duplicate(Rights::SAME_RIGHTS).unwrap();
19 let duplicated_vmo = Vmo::from(duplicated_handle);
20
21 RamdiskClientBuilder::new_with_vmo(duplicated_vmo, Some(ramdisk_block_size))
22 .build()
23 .await
24 .unwrap()
25}
26
27pub struct FvmInstance {
29 ramdisk: RamdiskClient,
30 fvm_instance: ServingMultiVolumeFilesystem,
31}
32
33pub struct FvmVolume {
36 serving_volume: ServingVolume,
37 guid: Guid,
38}
39
40impl FvmVolume {
41 pub fn new(serving_volume: ServingVolume, guid: Guid) -> Self {
43 Self { serving_volume, guid }
44 }
45
46 pub fn guid(&self) -> &Guid {
47 &self.guid
48 }
49
50 pub fn block_connector(&self) -> DirBasedBlockConnector {
51 let block_dir = fuchsia_fs::directory::clone(self.serving_volume.exposed_dir()).unwrap();
52 DirBasedBlockConnector::new(
53 block_dir,
54 format!("svc/{}", fidl_fuchsia_storage_block::BlockMarker::PROTOCOL_NAME),
55 )
56 }
57}
58
59impl FvmInstance {
60 pub async fn new(vmo: &Vmo, ramdisk_block_size: u64, fvm_slice_size: Option<u64>) -> Self {
63 let ramdisk = create_ramdisk(&vmo, ramdisk_block_size).await;
64
65 let mut fs = Filesystem::from_boxed_config(
66 ramdisk.connector().unwrap(),
67 Box::new(Fvm { slice_size: fvm_slice_size.unwrap_or(0), ..Fvm::dynamic_child() }),
68 );
69
70 if fvm_slice_size.is_some() {
71 fs.format().await.unwrap();
72 }
73
74 Self { ramdisk, fvm_instance: fs.serve_multi_volume().await.unwrap() }
75 }
76
77 pub async fn new_volume(
78 &mut self,
79 name: &str,
80 type_guid: &Guid,
81 initial_volume_size: Option<u64>,
82 ) -> FvmVolume {
83 let instance_guid = create_random_guid();
84
85 let create_options = fidl_fuchsia_fs_startup::CreateOptions {
86 initial_size: initial_volume_size,
87 guid: Some(instance_guid.clone()),
88 type_guid: Some(type_guid.clone()),
89 ..fidl_fuchsia_fs_startup::CreateOptions::default()
90 };
91
92 let mount_options = fidl_fuchsia_fs_startup::MountOptions::default();
93
94 let serving_volume =
95 self.fvm_instance.create_volume(name, create_options, mount_options).await.unwrap();
96
97 FvmVolume { serving_volume, guid: instance_guid }
98 }
99
100 pub async fn open_volume(&self, name: &str) -> FvmVolume {
101 let guid = self.fvm_instance.get_volume_info(name).await.unwrap().guid;
102 let serving_volume = self
103 .fvm_instance
104 .open_volume(name, fidl_fuchsia_fs_startup::MountOptions::default())
105 .await
106 .unwrap();
107 FvmVolume::new(serving_volume, guid.unwrap())
108 }
109
110 pub fn ramdisk_get_dir(&self) -> Option<&fio::DirectoryProxy> {
111 Some(self.ramdisk.outgoing())
112 }
113
114 pub async fn free_space(&self) -> u64 {
115 let info = self.fvm_instance.get_info().await.unwrap();
116 (info.slice_count - info.assigned_slice_count) * info.slice_size
117 }
118}