diff --git a/Cargo.lock b/Cargo.lock index aa3a2777863..46e1b1b7080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,26 +333,28 @@ dependencies = [ [[package]] name = "devicemapper" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1da7c273a50833e1fbbff5b71b06fd1f3f00356b0fa1d392a21ee8b4aabb2a1e" +version = "0.33.1" +source = "git+https://github.com/jbaublitz/devicemapper-rs?branch=stratisd-metadata-rework#b6f6a703701390548f553b020b95256fcf1128c6" dependencies = [ "bitflags", "devicemapper-sys", + "env_logger", "lazy_static", - "nix 0.24.3", + "log", + "nix 0.26.2", + "rand", + "retry", "semver", "serde", ] [[package]] name = "devicemapper-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2aad5bae6bc8a217f8c398c5737122966cbd35f19dd223433606225ec48285" +version = "0.1.5" +source = "git+https://github.com/jbaublitz/devicemapper-rs?branch=stratisd-metadata-rework#b6f6a703701390548f553b020b95256fcf1128c6" dependencies = [ - "bindgen 0.59.2", - "nix 0.24.3", + "bindgen 0.63.0", + "nix 0.26.2", ] [[package]] @@ -799,15 +801,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -848,18 +841,6 @@ dependencies = [ "void", ] -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "libc", - "memoffset 0.6.5", -] - [[package]] name = "nix" version = "0.26.2" @@ -869,7 +850,7 @@ dependencies = [ "bitflags", "cfg-if 1.0.0", "libc", - "memoffset 0.7.1", + "memoffset", "pin-utils", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index 371af4d74fd..41447a57a20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,8 @@ version = "2.3.0" optional = true [dependencies.devicemapper] -version = "0.32.3" +git = "https://github.com/jbaublitz/devicemapper-rs" +branch = "stratisd-metadata-rework" optional = true [dependencies.dbus] diff --git a/src/engine/strat_engine/backstore/backstore.rs b/src/engine/strat_engine/backstore/backstore.rs index 5823b25ba93..049e402ee92 100644 --- a/src/engine/strat_engine/backstore/backstore.rs +++ b/src/engine/strat_engine/backstore/backstore.rs @@ -10,7 +10,10 @@ use chrono::{DateTime, Utc}; use serde_json::Value; use tempfile::TempDir; -use devicemapper::{CacheDev, Device, DmDevice, LinearDev, Sectors}; +use devicemapper::{ + CacheDev, CacheDevTargetTable, CacheTargetParams, DevId, Device, DmDevice, DmFlags, DmOptions, + LinearDev, LinearDevTargetParams, LinearTargetParams, Sectors, TargetLine, TargetTable, +}; use crate::{ engine::{ @@ -52,6 +55,7 @@ fn make_cache( pool_uuid: PoolUuid, cache_tier: &CacheTier, origin: LinearDev, + cap: Option, new: bool, ) -> StratisResult { let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::MetaSub); @@ -80,6 +84,32 @@ fn make_cache( )?; let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::Cache); + if cap.is_some() { + let dm = get_dm(); + dm.device_suspend( + &DevId::Name(&dm_name), + DmOptions::default().set_flags(DmFlags::DM_SUSPEND), + )?; + let table = CacheDevTargetTable::new( + Sectors(0), + origin.size(), + CacheTargetParams::new( + meta.device(), + cache.device(), + origin.device(), + CACHE_BLOCK_SIZE, + vec!["writethrough".into()], + "default".to_owned(), + Vec::new(), + ), + ); + dm.table_load( + &DevId::Name(&dm_name), + &table.to_raw_table(), + DmOptions::default(), + )?; + dm.device_suspend(&DevId::Name(&dm_name), DmOptions::default())?; + }; Ok(CacheDev::setup( get_dm(), &dm_name, @@ -91,6 +121,18 @@ fn make_cache( )?) } +/// Set up the linear device on top of the data tier that can later be converted to a +/// cache device and serves as a placeholder for the device beneath encryption. +fn make_cap_linear_dev(pool_uuid: PoolUuid, origin: &LinearDev) -> Result { + let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::Cache); + let target = vec![TargetLine::new( + Sectors(0), + origin.size(), + LinearDevTargetParams::Linear(LinearTargetParams::new(origin.device(), Sectors(0))), + )]; + LinearDev::setup(get_dm(), &dm_name, Some(&dm_uuid), target).map_err(StratisError::from) +} + /// This structure can allocate additional space to the upper layer, but it /// cannot accept returned space. When it is extended to be able to accept /// returned space the allocation algorithm will have to be revised. @@ -105,6 +147,8 @@ pub struct Backstore { data_tier: DataTier, /// A linear DM device. linear: Option, + /// A placeholder device to be converted to cache. + cap_linear: Option, /// Index for managing allocation of cap device next: Sectors, } @@ -162,7 +206,7 @@ impl Backstore { } }; - let (cache_tier, cache, origin) = if !cachedevs.is_empty() { + let (cap_linear, cache_tier, cache, origin) = if !cachedevs.is_empty() { let block_mgr = BlockDevMgr::new(cachedevs, Some(last_update_time)); match backstore_save.cache_tier { Some(ref cache_tier_save) => { @@ -174,7 +218,8 @@ impl Backstore { } }; - let cache_device = match make_cache(pool_uuid, &cache_tier, origin, false) { + let cache_device = match make_cache(pool_uuid, &cache_tier, origin, None, false) + { Ok(cd) => cd, Err(e) => { return Err(( @@ -188,7 +233,7 @@ impl Backstore { )); } }; - (Some(cache_tier), Some(cache_device), None) + (None, Some(cache_tier), Some(cache_device), None) } None => { let err_msg = "Cachedevs exist, but cache metadata does not exist"; @@ -204,7 +249,11 @@ impl Backstore { } } } else { - (None, None, Some(origin)) + let cap_linear = match make_cap_linear_dev(pool_uuid, &origin) { + Ok(cap) => cap, + Err(e) => return Err((e, data_tier.block_mgr.into_bdas())), + }; + (Some(cap_linear), None, None, Some(origin)) }; Ok(Backstore { @@ -212,6 +261,7 @@ impl Backstore { cache_tier, linear: origin, cache, + cap_linear, next: backstore_save.cap.allocs[0].1, }) } @@ -245,6 +295,7 @@ impl Backstore { cache_tier: None, linear: None, cache: None, + cap_linear: None, next: Sectors(0), }) } @@ -287,8 +338,11 @@ impl Backstore { let linear = self.linear .take() .expect("some space has already been allocated from the backstore => (cache_tier.is_none() <=> self.linear.is_some())"); + let cap = self.cap_linear + .take() + .expect("some space has already been allocated from the backstore => (cache_tier.is_none() <=> self.cap_linear.is_some())"); - let cache = make_cache(pool_uuid, &cache_tier, linear, true)?; + let cache = make_cache(pool_uuid, &cache_tier, linear, Some(cap), true)?; self.cache = Some(cache); @@ -369,7 +423,7 @@ impl Backstore { /// device if it does not already exist. Return an error if DM /// operations fail. Use all segments currently allocated in the data tier. fn extend_cap_device(&mut self, pool_uuid: PoolUuid) -> StratisResult<()> { - let create = match (self.cache.as_mut(), self.linear.as_mut()) { + let create = match (self.cache.as_mut(), self.cap_linear.as_mut()) { (None, None) => true, (Some(cache), None) => { let table = self.data_tier.segments.map_to_dm(); @@ -390,7 +444,9 @@ impl Backstore { let table = self.data_tier.segments.map_to_dm(); let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::OriginSub); let origin = LinearDev::setup(get_dm(), &dm_name, Some(&dm_uuid), table)?; + let cap = make_cap_linear_dev(pool_uuid, &origin)?; self.linear = Some(origin); + self.cap_linear = Some(cap); } Ok(()) @@ -613,7 +669,7 @@ impl Backstore { self.cache .as_ref() .map(|d| d.device()) - .or_else(|| self.linear.as_ref().map(|d| d.device())) + .or_else(|| self.cap_linear.as_ref().map(|d| d.device())) } /// Lookup an immutable blockdev by its Stratis UUID.