From 0cba3d1a88a2cce1b9bb71e3d5d80d324d4f8f3a Mon Sep 17 00:00:00 2001 From: Patrick Mooney Date: Tue, 9 Jan 2024 23:01:33 -0600 Subject: [PATCH] Add crucible-mem backend --- bin/propolis-standalone/src/config.rs | 32 ++++++++++++++++++++++ lib/propolis/src/block/crucible.rs | 39 +++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/bin/propolis-standalone/src/config.rs b/bin/propolis-standalone/src/config.rs index b448ba3f8..e0df2912e 100644 --- a/bin/propolis-standalone/src/config.rs +++ b/bin/propolis-standalone/src/config.rs @@ -81,6 +81,7 @@ pub fn block_backend( (be, creg) } "crucible" => create_crucible_backend(be, opts, log), + "crucible-mem" => create_crucible_mem_backend(be, opts, log), "mem-async" => { let parsed: MemAsyncConfig = opt_deser(&be.options).unwrap(); @@ -256,6 +257,25 @@ fn create_crucible_backend( (be, creg) } +#[cfg(feature = "crucible")] +fn create_crucible_mem_backend( + be: &propolis_standalone_config::BlockDevice, + opts: block::BackendOpts, + log: &slog::Logger, +) -> (Arc, ChildRegister) { + #[derive(Deserialize)] + struct CrucibleMemConfig { + size: u64, + } + let parsed: CrucibleMemConfig = opt_deser(&be.options).unwrap(); + + let be = block::CrucibleBackend::create_mem(parsed.size, opts, log.clone()) + .unwrap(); + let creg = + ChildRegister::new(&be, Some(be.get_uuid().unwrap().to_string())); + (be, creg) +} + #[cfg(not(feature = "crucible"))] fn create_crucible_backend( _be: &propolis_standalone_config::BlockDevice, @@ -267,3 +287,15 @@ fn create_crucible_backend( order to use the crucible block backend" ); } + +#[cfg(not(feature = "crucible"))] +fn create_crucible_mem_backend( + _be: &propolis_standalone_config::BlockDevice, + _opts: block::BackendOpts, + _log: &slog::Logger, +) -> (Arc, ChildRegister) { + panic!( + "Rebuild propolis-standalone with 'crucible' feature enabled in \ + order to use the crucible-mem block backend" + ); +} diff --git a/lib/propolis/src/block/crucible.rs b/lib/propolis/src/block/crucible.rs index c3bad7057..3a403e7e8 100644 --- a/lib/propolis/src/block/crucible.rs +++ b/lib/propolis/src/block/crucible.rs @@ -161,6 +161,45 @@ impl CrucibleBackend { })) } + /// Create Crucible backend using the in-memory volume backend, rather than + /// "real" Crucible downstairs instances. + pub fn create_mem( + size: u64, + opts: block::BackendOpts, + log: slog::Logger, + ) -> io::Result> { + let rt = tokio::runtime::Handle::current(); + rt.block_on(async move { + let block_size = opts.block_size.ok_or_else(|| { + CrucibleError::GenericError( + "block_size is required parameter".into(), + ) + })? as u64; + // Allocate and construct the volume. + let mem_disk = Arc::new(crucible::InMemoryBlockIO::new( + Uuid::new_v4(), + block_size, + size as usize, + )); + let mut volume = Volume::new(block_size, log); + volume.add_subvolume(mem_disk).await?; + + Ok(Arc::new(CrucibleBackend { + state: Arc::new(WorkerState { + attachment: block::backend::Attachment::new(), + volume, + info: block::DeviceInfo { + block_size: block_size as u32, + total_size: size / block_size, + read_only: opts.read_only.unwrap_or(false), + }, + skip_flush: opts.skip_flush.unwrap_or(false), + }), + })) + }) + .map_err(CrucibleError::into) + } + // Communicate to Nexus that we can remove the read only parent for // the given volume id. async fn remove_read_only_parent(