| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::instance_actor::InstanceActor; |
| use crate::volume::VolumeConnection; |
| use crate::volume_actor::VolumeActor; |
| use crate::Args; |
| use async_trait::async_trait; |
| use fuchsia_zircon::Vmo; |
| use futures::lock::Mutex; |
| use rand::rngs::SmallRng; |
| use rand::{Rng, SeedableRng}; |
| use std::sync::Arc; |
| use std::time::Duration; |
| use storage_stress_test_utils::fvm::{FvmInstance, Guid}; |
| use stress_test::actor::ActorRunner; |
| use stress_test::environment::Environment; |
| use stress_test::random_seed; |
| |
| // All partitions in this test have their type set to this arbitrary GUID. |
| const TYPE_GUID: Guid = |
| [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf]; |
| |
| /// Describes the environment that this blobfs stress test will run under. |
| pub struct FvmEnvironment { |
| seed: u64, |
| args: Args, |
| vmo: Vmo, |
| instance_actor: Arc<Mutex<InstanceActor>>, |
| volume_actors: Vec<(Guid, Arc<Mutex<VolumeActor>>)>, |
| } |
| |
| impl FvmEnvironment { |
| pub async fn new(args: Args) -> Self { |
| // Create the VMO that the ramdisk is backed by |
| let vmo_size = args.ramdisk_block_count * args.ramdisk_block_size; |
| let vmo = Vmo::create(vmo_size).unwrap(); |
| |
| // Create a ramdisk and setup FVM. |
| let mut fvm = |
| FvmInstance::new(true, &vmo, args.fvm_slice_size, args.ramdisk_block_size).await; |
| |
| // Create the root RNG |
| let seed = match args.seed { |
| Some(seed) => seed, |
| None => random_seed(), |
| }; |
| let mut rng = SmallRng::seed_from_u64(seed); |
| |
| let mut volume_actors = vec![]; |
| for i in 0..args.num_volumes { |
| // Create the new volume |
| let volume_name = format!("testpart-{}", i); |
| let volume_guid = fvm.new_volume(&volume_name, &TYPE_GUID, None).await; |
| |
| // Connect to the volume |
| let volume = VolumeConnection::new(&volume_guid, args.fvm_slice_size).await; |
| |
| // Create the actor |
| let rng = SmallRng::from_seed(rng.gen()); |
| let volume_actor = Arc::new(Mutex::new( |
| VolumeActor::new(volume, rng, args.max_slices_in_extend, args.max_vslice_count) |
| .await, |
| )); |
| |
| volume_actors.push((volume_guid, volume_actor)); |
| } |
| |
| let instance_actor = Arc::new(Mutex::new(InstanceActor::new(fvm))); |
| |
| Self { seed, args, vmo, instance_actor, volume_actors } |
| } |
| } |
| |
| impl std::fmt::Debug for FvmEnvironment { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| f.debug_struct("Environment").field("seed", &self.seed).field("args", &self.args).finish() |
| } |
| } |
| |
| #[async_trait] |
| impl Environment for FvmEnvironment { |
| fn target_operations(&self) -> Option<u64> { |
| self.args.num_operations |
| } |
| |
| fn timeout_seconds(&self) -> Option<u64> { |
| self.args.time_limit_secs |
| } |
| |
| async fn actor_runners(&mut self) -> Vec<ActorRunner> { |
| let mut runners = vec![]; |
| |
| for (guid, actor) in &self.volume_actors { |
| let actor_name = format!("volume_actor_{}", guid[0]); |
| runners.push(ActorRunner::new(actor_name, None, actor.clone())); |
| } |
| |
| if let Some(secs) = self.args.disconnect_secs { |
| if secs > 0 { |
| runners.push(ActorRunner::new( |
| "instance_actor", |
| Some(Duration::from_secs(secs)), |
| self.instance_actor.clone(), |
| )) |
| } |
| } |
| |
| runners |
| } |
| |
| async fn reset(&mut self) { |
| { |
| let mut actor = self.instance_actor.lock().await; |
| |
| // The environment is only reset when the instance is killed. |
| // TODO(72385): Pass the actor error here, so it can be printed out on assert failure. |
| assert!(actor.instance.is_none()); |
| |
| // Start isolated-devmgr and FVM |
| let fvm = FvmInstance::new( |
| false, |
| &self.vmo, |
| self.args.fvm_slice_size, |
| self.args.ramdisk_block_size, |
| ) |
| .await; |
| |
| // Replace the FVM instance |
| actor.instance = Some(fvm); |
| } |
| |
| for (guid, actor) in &self.volume_actors { |
| let mut actor = actor.lock().await; |
| |
| // Connect to the volume |
| let volume = VolumeConnection::new(guid, self.args.fvm_slice_size).await; |
| |
| // Replace the volume |
| actor.volume = volume; |
| } |
| } |
| } |