diff --git a/src/engine/strat_engine/backstore/backstore.rs b/src/engine/strat_engine/backstore/backstore.rs index 1f6b8b9d4d..6597402058 100644 --- a/src/engine/strat_engine/backstore/backstore.rs +++ b/src/engine/strat_engine/backstore/backstore.rs @@ -511,25 +511,17 @@ impl Backstore { self.data_tier.destroy() } - /// Run code required to stop a pool on backstore data structures. - pub fn stop(&mut self) -> StratisResult<()> { - self.data_tier.block_mgr.teardown() - } - /// Teardown the DM devices in the backstore. - #[cfg(test)] pub fn teardown(&mut self) -> StratisResult<()> { match self.cache { - Some(ref mut cache) => cache.teardown(get_dm()), + Some(ref mut cache) => cache.teardown(get_dm())?, None => { if let Some(ref mut linear) = self.linear { - linear.teardown(get_dm()) - } else { - Ok(()) + linear.teardown(get_dm())?; } } - } - .map_err(|e| e.into()) + }; + self.data_tier.block_mgr.teardown() } /// Return the device that this tier is currently using. diff --git a/src/engine/strat_engine/backstore/blockdev.rs b/src/engine/strat_engine/backstore/blockdev.rs index 2f524eda61..cd269e33f9 100644 --- a/src/engine/strat_engine/backstore/blockdev.rs +++ b/src/engine/strat_engine/backstore/blockdev.rs @@ -302,6 +302,10 @@ impl StratBlockDev { /// physical device. pub fn teardown(&mut self) -> StratisResult<()> { if let Some(ch) = self.underlying_device.crypt_handle() { + debug!( + "Deactivating unlocked encrypted device with UUID {}", + self.bda.dev_uuid() + ); ch.deactivate() } else { Ok(()) diff --git a/src/engine/strat_engine/liminal/liminal.rs b/src/engine/strat_engine/liminal/liminal.rs index 22609b01bf..0956aaa5ec 100644 --- a/src/engine/strat_engine/liminal/liminal.rs +++ b/src/engine/strat_engine/liminal/liminal.rs @@ -271,164 +271,95 @@ impl LiminalDevices { &mut self, pools: &Table, pool_uuid: PoolUuid, - infos: DeviceSet, + device_set: DeviceSet, ) -> StratisResult<(Name, StratPool)> { - assert!(pools.get_by_uuid(pool_uuid).is_none()); - assert!(self.stopped_pools.get(&pool_uuid).is_none()); - - let (bdas, timestamp, metadata) = load_stratis_metadata(pool_uuid, &infos)?; - self.setup_pool(pools, pool_uuid, infos, bdas, timestamp, metadata) - } - - /// Variantion on try_setup_pool That returns None if the pool is marked - /// as stopped in its metadata. - /// - /// Precondition: pools.get_by_uuid(pool_uuid).is_none() && - /// self.stopped_pools.get(pool_uuid).is_none() - fn try_setup_started_pool( - &mut self, - pools: &Table, - pool_uuid: PoolUuid, - infos: DeviceSet, - ) -> Option<(Name, StratPool)> { - fn try_setup_started_pool_failure( - liminal_devices: &mut LiminalDevices, + fn try_setup_pool_failure( pools: &Table, pool_uuid: PoolUuid, - infos: DeviceSet, - ) -> StratisResult> { + device_set: &DeviceSet, + ) -> StratisResult<(Name, StratPool)> { + let infos = match device_set.as_opened_set() { + Some(i) => i, + None => { + return Err(StratisError::Msg(format!( + "Some of the devices in pool with UUID {} are unopened", + pool_uuid, + ))) + } + }; let (bdas, timestamp, metadata) = load_stratis_metadata(pool_uuid, &infos)?; - if let Some(true) | None = metadata.started { - liminal_devices - .setup_pool(pools, pool_uuid, infos, bdas, timestamp, metadata) - .map(Some) - } else { - liminal_devices.stopped_pools.insert(pool_uuid, infos); - Ok(None) - } + setup_pool( + pools, pool_uuid, device_set, &infos, bdas, timestamp, metadata, + ) } assert!(pools.get_by_uuid(pool_uuid).is_none()); assert!(self.stopped_pools.get(&pool_uuid).is_none()); - match try_setup_started_pool_failure(self, pools, pool_uuid, infos) { - Ok(opt) => opt, + match try_setup_pool_failure(pools, pool_uuid, &device_set) { + Ok((name, pool)) => { + self.uuid_lookup = self + .uuid_lookup + .drain() + .filter(|(_, (p, _))| *p != pool_uuid) + .collect(); + info!( + "Pool with name \"{}\" and UUID \"{}\" set up", + name, pool_uuid + ); + Ok((name, pool)) + } Err(err) => { info!("Attempt to set up pool failed, but it may be possible to set up the pool later, if the situation changes: {}", err); - None + if !device_set.is_empty() { + self.stopped_pools.insert(pool_uuid, device_set); + } + Err(err) } } } - /// Given a set of devices, try to set up a pool. - /// Return the pool information if a pool is set up. Otherwise, return - /// the pool information to the stopped pools data structure. - /// Do not attempt setup if the pool contains any unopened devices. - /// - /// If there is a name conflict between the set of devices in devices - /// and some existing pool, return an error. + /// Variation on try_setup_pool that returns None if the pool is marked + /// as stopped in its metadata. /// - fn setup_pool( + /// Precondition: pools.get_by_uuid(pool_uuid).is_none() && + /// self.stopped_pools.get(pool_uuid).is_none() + fn try_setup_started_pool( &mut self, pools: &Table, pool_uuid: PoolUuid, device_set: DeviceSet, - bdas: HashMap, - timestamp: DateTime, - metadata: PoolSave, - ) -> StratisResult<(Name, StratPool)> { - /// Setup a pool from constituent devices in the context of some already - /// setup pools. - fn setup_pool_checks( + ) -> Option<(Name, StratPool)> { + fn try_setup_started_pool_failure( pools: &Table, pool_uuid: PoolUuid, device_set: &DeviceSet, - infos: &HashMap, - bdas: HashMap, - timestamp: DateTime, - metadata: PoolSave, - ) -> StratisResult<(Name, StratPool)> { - if let Some((uuid, _)) = pools.get_by_name(&metadata.name) { - return Err( - StratisError::Msg(format!( - "There is a pool name conflict. The devices currently being processed have been identified as belonging to the pool with UUID {} and name {}, but a pool with the same name and UUID {} is already active", + ) -> StratisResult> { + let infos = match device_set.as_opened_set() { + Some(i) => i, + None => { + return Err(StratisError::Msg(format!( + "Some of the devices in pool with UUID {} are unopened", pool_uuid, - &metadata.name, - uuid - ))); - } - - let (datadevs, cachedevs) = match get_blockdevs(&metadata.backstore, infos, bdas) { - Err(err) => return Err( - StratisError::Chained( - format!( - "There was an error encountered when calculating the block devices for pool with UUID {} and name {}", - pool_uuid, - &metadata.name, - ), - Box::new(err) - )), - Ok((datadevs, cachedevs)) => (datadevs, cachedevs), - }; - - if datadevs.get(0).is_none() { - return Err(StratisError::Msg(format!( - "There do not appear to be any data devices in the set with pool UUID {}", - pool_uuid - ))); - } - - let encryption_info = match device_set.encryption_info() { - Ok(opt) => opt, - Err(_) => { - // NOTE: This is not actually a hopeless situation. It may be - // that a LUKS device owned by Stratis corresponding to a - // Stratis device has just not been discovered yet. If it - // is, the appropriate info will be updated, and setup may - // yet succeed. - return Err( - StratisError::Msg(format!( - "Some data devices in the set belonging to pool with UUID {} and name {} appear to be encrypted devices managed by Stratis, and some do not", - pool_uuid, - &metadata.name - ))); + ))) } }; - - let state = get_pool_state(encryption_info); - StratPool::setup(pool_uuid, datadevs, cachedevs, timestamp, &metadata, state).map_err( - |err| { - StratisError::Chained( - format!( - "An attempt to set up pool with UUID {} from the assembled devices failed", - pool_uuid - ), - Box::new(err), - ) - }, - ) + let (bdas, timestamp, metadata) = load_stratis_metadata(pool_uuid, &infos)?; + if let Some(true) | None = metadata.started { + setup_pool( + pools, pool_uuid, device_set, &infos, bdas, timestamp, metadata, + ) + .map(Some) + } else { + Ok(None) + } } - let infos = match device_set.as_opened_set() { - Some(i) => i, - None => { - return Err(StratisError::Msg(format!( - "Some of the devices in pool with UUID {} are unopened", - pool_uuid, - ))) - } - }; + assert!(pools.get_by_uuid(pool_uuid).is_none()); + assert!(self.stopped_pools.get(&pool_uuid).is_none()); - match setup_pool_checks( - pools, - pool_uuid, - &device_set, - &infos, - bdas, - timestamp, - metadata, - ) { - Ok((pool_name, pool)) => { + match try_setup_started_pool_failure(pools, pool_uuid, &device_set) { + Ok(Some((name, pool))) => { self.uuid_lookup = self .uuid_lookup .drain() @@ -436,16 +367,22 @@ impl LiminalDevices { .collect(); info!( "Pool with name \"{}\" and UUID \"{}\" set up", - pool_name, pool_uuid + name, pool_uuid ); - Ok((pool_name, pool)) + Some((name, pool)) + } + Ok(None) => { + if !device_set.is_empty() { + self.stopped_pools.insert(pool_uuid, device_set); + } + None } Err(err) => { info!("Attempt to set up pool failed, but it may be possible to set up the pool later, if the situation changes: {}", err); - if !infos.is_empty() { + if !device_set.is_empty() { self.stopped_pools.insert(pool_uuid, device_set); } - Err(err) + None } } } @@ -462,11 +399,20 @@ impl LiminalDevices { event: &UdevEngineEvent, ) -> Option<(Name, PoolUuid, StratPool)> { let event_type = event.event_type(); - let device_info = identify_block_device(event); let device_path = match event.device().devnode() { Some(d) => d, None => return None, }; + let device_info = match event_type { + libudev::EventType::Add | libudev::EventType::Change => { + if device_path.exists() { + identify_block_device(event) + } else { + None + } + } + _ => None, + }; if event_type == libudev::EventType::Add || (event_type == libudev::EventType::Change && device_info.is_some()) @@ -555,19 +501,9 @@ impl<'a> Into for &'a LiminalDevices { /// determined to be a part of the same pool. fn load_stratis_metadata( pool_uuid: PoolUuid, - device_set: &DeviceSet, + infos: &HashMap, ) -> StratisResult<(HashMap, DateTime, PoolSave)> { - let infos = match device_set.as_opened_set() { - Some(i) => i, - None => { - return Err(StratisError::Msg(format!( - "Some of the devices in pool with UUID {} are unopened", - pool_uuid, - ))) - } - }; - - let bdas = match get_bdas(&infos) { + let bdas = match get_bdas(infos) { Err(err) => Err(StratisError::Chained( format!( "There was an error encountered when reading the BDAs for the devices found for pool with UUID {}", @@ -590,7 +526,7 @@ fn load_stratis_metadata( ))); } - match get_metadata(&infos, &bdas) { + match get_metadata(infos, &bdas) { Err(err) => Err( StratisError::Chained( format!( @@ -606,3 +542,78 @@ fn load_stratis_metadata( Ok(Some((timestamp, metadata))) => Ok((bdas, timestamp, metadata)), } } + +/// Given a set of devices, try to set up a pool. +/// Return the pool information if a pool is set up. Otherwise, return +/// the pool information to the stopped pools data structure. +/// Do not attempt setup if the pool contains any unopened devices. +/// +/// If there is a name conflict between the set of devices in devices +/// and some existing pool, return an error. +fn setup_pool( + pools: &Table, + pool_uuid: PoolUuid, + device_set: &DeviceSet, + infos: &HashMap, + bdas: HashMap, + timestamp: DateTime, + metadata: PoolSave, +) -> StratisResult<(Name, StratPool)> { + if let Some((uuid, _)) = pools.get_by_name(&metadata.name) { + return Err( + StratisError::Msg(format!( + "There is a pool name conflict. The devices currently being processed have been identified as belonging to the pool with UUID {} and name {}, but a pool with the same name and UUID {} is already active", + pool_uuid, + &metadata.name, + uuid + ))); + } + + let (datadevs, cachedevs) = match get_blockdevs(&metadata.backstore, infos, bdas) { + Err(err) => return Err( + StratisError::Chained( + format!( + "There was an error encountered when calculating the block devices for pool with UUID {} and name {}", + pool_uuid, + &metadata.name, + ), + Box::new(err) + )), + Ok((datadevs, cachedevs)) => (datadevs, cachedevs), + }; + + if datadevs.get(0).is_none() { + return Err(StratisError::Msg(format!( + "There do not appear to be any data devices in the set with pool UUID {}", + pool_uuid + ))); + } + + let encryption_info = match device_set.encryption_info() { + Ok(opt) => opt, + Err(_) => { + // NOTE: This is not actually a hopeless situation. It may be + // that a LUKS device owned by Stratis corresponding to a + // Stratis device has just not been discovered yet. If it + // is, the appropriate info will be updated, and setup may + // yet succeed. + return Err( + StratisError::Msg(format!( + "Some data devices in the set belonging to pool with UUID {} and name {} appear to be encrypted devices managed by Stratis, and some do not", + pool_uuid, + &metadata.name + ))); + } + }; + + let state = get_pool_state(encryption_info); + StratPool::setup(pool_uuid, datadevs, cachedevs, timestamp, &metadata, state).map_err(|err| { + StratisError::Chained( + format!( + "An attempt to set up pool with UUID {} from the assembled devices failed", + pool_uuid + ), + Box::new(err), + ) + }) +} diff --git a/src/engine/strat_engine/pool.rs b/src/engine/strat_engine/pool.rs index b83111e1e5..c6332544a3 100644 --- a/src/engine/strat_engine/pool.rs +++ b/src/engine/strat_engine/pool.rs @@ -363,7 +363,7 @@ impl StratPool { data.started = Some(false); let json = serde_json::to_string(&data)?; self.backstore.save_state(json.as_bytes())?; - self.backstore.stop()?; + self.backstore.teardown()?; Ok(self .backstore .blockdevs()