Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/engine/strat_engine/backstore/blockdev/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ impl StratBlockDev {
&self.devnode
}

/// Return the allocations for integrity metadata on this block device.
pub fn meta_allocs(&self) -> Vec<(Sectors, Sectors)> {
self.integrity_meta_allocs.clone()
}

/// Scan the block device specified by physical_path for its size.
pub fn scan_blkdev_size(physical_path: &Path) -> StratisResult<Sectors> {
Ok(blkdev_size(&File::open(physical_path)?)?.sectors())
Expand Down
135 changes: 135 additions & 0 deletions src/engine/strat_engine/backstore/integrity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::{hash_map::Entry, HashMap};

use devicemapper::{
Device, LinearDev, LinearDevTargetParams, LinearTargetParams, Sectors, TargetLine,
};

use crate::{
engine::{
strat_engine::{
backstore::{blockdev::v2::StratBlockDev, data_tier::DataTier},
dm::get_dm,
names::{format_integrity_ids, IntegrityRole},
},
types::PoolUuid,
},
stratis::{StratisError, StratisResult},
};

type IntegritySegments = (
HashMap<Device, Vec<(Sectors, Sectors)>>,
HashMap<Device, Vec<(Sectors, Sectors)>>,
);

/// Generate a better format for the integrity data and metadata segments when setting up the
/// linear devices.
#[allow(dead_code)]
fn generate_segments_from_metadata(
data_tier: DataTier<StratBlockDev>,
) -> StratisResult<IntegritySegments> {
let data_segments = data_tier
.segments
.inner
.iter()
.try_fold::<_, _, StratisResult<_>>(
HashMap::new(),
|mut hash: HashMap<_, Vec<(Sectors, Sectors)>>, seg| {
let (_, blockdev) = data_tier.get_blockdev_by_uuid(seg.uuid).ok_or_else(|| {
StratisError::Msg(format!(
"No record of device with UUID {} found in active block device manager",
seg.uuid
))
})?;
match hash.entry(*blockdev.device()) {
Entry::Occupied(mut entry) => {
entry
.get_mut()
.push((seg.segment.start, seg.segment.length));
}
Entry::Vacant(entry) => {
entry.insert(vec![(seg.segment.start, seg.segment.length)]);
}
};
Ok(hash)
},
)?;

let meta_segments = data_tier.blockdevs().into_iter().fold(
HashMap::new(),
|mut hash: HashMap<_, Vec<(Sectors, Sectors)>>, (_, bd)| {
match hash.entry(*bd.device()) {
Entry::Occupied(mut entry) => entry.get_mut().extend(bd.meta_allocs()),
Entry::Vacant(entry) => {
entry.insert(bd.meta_allocs());
}
};
hash
},
);

Ok((data_segments, meta_segments))
}

/// Set up a linear device to be used as an integrity subdevice from a record of allocations in the
/// metadata.
fn setup_linear_dev(
pool_uuid: PoolUuid,
devno: Device,
role: IntegrityRole,
info: &HashMap<Device, Vec<(Sectors, Sectors)>>,
) -> StratisResult<LinearDev> {
let (name, uuid) = format_integrity_ids(pool_uuid, role);
let (_, linear_table) = info
.get(&devno)
.ok_or_else(|| {
StratisError::Msg(format!(
"Failed to find a record of allocations for device number {devno}"
))
})?
.iter()
.fold(
(Sectors(0), Vec::new()),
|(mut offset, mut vec), (start, length)| {
vec.push(TargetLine::new(
offset,
*length,
LinearDevTargetParams::Linear(LinearTargetParams::new(devno, *start)),
));
offset += *length;
(offset, vec)
},
);
LinearDev::setup(get_dm(), &name, Some(&uuid), linear_table).map_err(StratisError::from)
}

/// Represents a handle to the integrity layer of the devicemapper stack.
#[allow(dead_code)]
pub struct IntegrityLayer {
data: LinearDev,
meta: LinearDev,
}

impl IntegrityLayer {
/// Initialize the integrity layer for a pool.
#[allow(dead_code)]
fn initialize(
pool_uuid: PoolUuid,
devno: Device,
data_segments: &HashMap<Device, Vec<(Sectors, Sectors)>>,
metadata_segments: &HashMap<Device, Vec<(Sectors, Sectors)>>,
) -> StratisResult<Self> {
let data_dev = setup_linear_dev(pool_uuid, devno, IntegrityRole::OriginSub, data_segments)?;

let meta_dev =
setup_linear_dev(pool_uuid, devno, IntegrityRole::MetaSub, metadata_segments)?;

Ok(IntegrityLayer {
data: data_dev,
meta: meta_dev,
})
}
}
1 change: 1 addition & 0 deletions src/engine/strat_engine/backstore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod blockdevmgr;
mod cache_tier;
mod data_tier;
mod devices;
mod integrity;
mod range_alloc;
mod shared;

Expand Down
38 changes: 38 additions & 0 deletions src/engine/strat_engine/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,19 @@ pub enum CacheRole {
OriginSub,
}

/// The various roles taken on by DM devices in the integrity tier.
#[derive(Clone, Copy, strum_macros::Display)]
#[strum(serialize_all = "lowercase")]
pub enum IntegrityRole {
/// The DM integrity device, contains the other two devices.
#[allow(dead_code)]
Integrity,
/// The meta sub-device of the DM integrity device.
MetaSub,
/// The origin sub-device of the DM integrity device, holds the actual data.
OriginSub,
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
Expand Down Expand Up @@ -236,6 +249,31 @@ pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf,
)
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
/// + len("stratis") 7
/// + len("private") 7
/// + len("integrity") 9
/// + num_dashes 5
/// + len(pool uuid) 32
/// + max(len(IntegrityRole)) 9
/// < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_integrity_ids(pool_uuid: PoolUuid, role: IntegrityRole) -> (DmNameBuf, DmUuidBuf) {
let value = format!(
"stratis-{}-private-{}-integrity-{}",
FORMAT_VERSION,
uuid_to_string!(pool_uuid),
role
);
(
DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 60"),
DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 61"),
)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down