diff --git a/src/bin/utils/cmds.rs b/src/bin/utils/cmds.rs index 58ce808de0..24571486f3 100644 --- a/src/bin/utils/cmds.rs +++ b/src/bin/utils/cmds.rs @@ -16,6 +16,8 @@ use log::LevelFilter; use devicemapper::Bytes; +use stratisd::engine::IntegrityTagSpec; + use crate::utils::predict_usage; #[cfg(feature = "systemd_compat")] @@ -91,7 +93,7 @@ pool is encrypted, setting this option has no effect on the prediction."), Arg::new("integrity_tag_size") .long("integrity-tag-size") .num_args(1) - .help("Size of the integrity checksums to be stored in the integrity metadata. The checksum size depends on the algorithm used for checksums. Units are bytes.") + .help("Size of the integrity tag to stored a checksum or other value for each block on a device.") .next_line_help(true) ) .arg( @@ -154,7 +156,7 @@ impl<'a> UtilCommand<'a> for StratisPredictUsage { .transpose()?, sub_m .get_one::("integrity_tag_size") - .map(|s| s.parse::().map(Bytes::from)) + .map(|sz| IntegrityTagSpec::try_from(sz.as_str())) .transpose()?, LevelFilter::from_str( matches diff --git a/src/bin/utils/predict_usage.rs b/src/bin/utils/predict_usage.rs index 1c9d602f05..0c2f81f985 100644 --- a/src/bin/utils/predict_usage.rs +++ b/src/bin/utils/predict_usage.rs @@ -14,7 +14,7 @@ use serde_json::{json, Value}; use devicemapper::{Bytes, Sectors}; use stratisd::engine::{ - crypt_metadata_size, integrity_meta_space, ThinPoolSizeParams, BDA, + crypt_metadata_size, integrity_meta_space, IntegrityTagSpec, ThinPoolSizeParams, BDA, DEFAULT_INTEGRITY_BLOCK_SIZE, DEFAULT_INTEGRITY_JOURNAL_SIZE, DEFAULT_INTEGRITY_TAG_SIZE, }; @@ -167,7 +167,7 @@ pub fn predict_filesystem_usage( fn predict_pool_metadata_usage( device_sizes: Vec, journal_size: Option, - tag_size: Option, + tag_size: Option, ) -> Result> { let stratis_metadata_alloc = BDA::default().extended_size().sectors(); let stratis_avail_sizes = device_sizes @@ -218,7 +218,7 @@ pub fn predict_pool_usage( device_sizes: Vec, filesystem_sizes: Option>, journal_size: Option, - tag_size: Option, + tag_size: Option, log_level: LevelFilter, ) -> Result<(), Box> { Builder::new().filter(None, log_level).init(); diff --git a/src/dbus_api/api/manager_3_8/api.rs b/src/dbus_api/api/manager_3_8/api.rs index 37067df11c..a7a0658a07 100644 --- a/src/dbus_api/api/manager_3_8/api.rs +++ b/src/dbus_api/api/manager_3_8/api.rs @@ -60,13 +60,14 @@ pub fn create_pool_method(f: &Factory, TData>) -> Method, TData>) -> MethodResult { Some(get_next_arg(&mut iter, 3)?), ); let journal_size_tuple: (bool, u64) = get_next_arg(&mut iter, 4)?; - let tag_size_tuple: (bool, u8) = get_next_arg(&mut iter, 5)?; + let tag_size_tuple: (bool, String) = get_next_arg(&mut iter, 5)?; let return_message = message.method_return(); @@ -188,7 +188,16 @@ pub fn create_pool(m: &MethodInfo<'_, MTSync, TData>) -> MethodResult { }; let journal_size = tuple_to_option(journal_size_tuple).map(Bytes::from); - let tag_size = tuple_to_option(tag_size_tuple).map(Bytes::from); + let tag_size = match tuple_to_option(tag_size_tuple) + .map(|s| IntegrityTagSpec::try_from(s.as_str())) + .transpose() + { + Ok(s) => s, + Err(e) => { + let (rc, rs) = engine_to_dbus_err_tuple(&e); + return Ok(vec![return_message.append3(default_return, rc, rs)]); + } + }; let dbus_context = m.tree.get_data(); let create_result = handle_action!(block_on(dbus_context.engine.create_pool( diff --git a/src/engine/engine.rs b/src/engine/engine.rs index ed16f88e6e..8ffdfe51cf 100644 --- a/src/engine/engine.rs +++ b/src/engine/engine.rs @@ -21,11 +21,12 @@ use crate::{ structures::{AllLockReadGuard, AllLockWriteGuard, SomeLockReadGuard, SomeLockWriteGuard}, types::{ ActionAvailability, BlockDevTier, Clevis, CreateAction, DeleteAction, DevUuid, - EncryptionInfo, FilesystemUuid, GrowAction, Key, KeyDescription, LockedPoolsInfo, - MappingCreateAction, MappingDeleteAction, Name, PoolDiff, PoolEncryptionInfo, - PoolIdentifier, PoolUuid, RegenAction, RenameAction, ReportType, SetCreateAction, - SetDeleteAction, SetUnlockAction, StartAction, StopAction, StoppedPoolsInfo, - StratFilesystemDiff, StratSigblockVersion, UdevEngineEvent, UnlockMethod, + EncryptionInfo, FilesystemUuid, GrowAction, IntegrityTagSpec, Key, KeyDescription, + LockedPoolsInfo, MappingCreateAction, MappingDeleteAction, Name, PoolDiff, + PoolEncryptionInfo, PoolIdentifier, PoolUuid, RegenAction, RenameAction, ReportType, + SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction, + StoppedPoolsInfo, StratFilesystemDiff, StratSigblockVersion, UdevEngineEvent, + UnlockMethod, }, }, stratis::StratisResult, @@ -382,7 +383,7 @@ pub trait Engine: Debug + Report + Send + Sync { blockdev_paths: &[&Path], encryption_info: Option<&EncryptionInfo>, journal_size: Option, - tag_size: Option, + tag_size: Option, ) -> StratisResult>; /// Handle a libudev event. diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 468fac880b..9fade9022f 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -21,8 +21,8 @@ pub use self::{ structures::{AllLockReadGuard, ExclusiveGuard, SharedGuard, Table}, types::{ ActionAvailability, BlockDevTier, ClevisInfo, CreateAction, DeleteAction, DevUuid, Diff, - EncryptionInfo, EngineAction, FilesystemUuid, GrowAction, KeyDescription, Lockable, - LockedPoolInfo, LockedPoolsInfo, MappingCreateAction, MappingDeleteAction, + EncryptionInfo, EngineAction, FilesystemUuid, GrowAction, IntegrityTagSpec, KeyDescription, + Lockable, LockedPoolInfo, LockedPoolsInfo, MappingCreateAction, MappingDeleteAction, MaybeInconsistent, Name, PoolDiff, PoolEncryptionInfo, PoolIdentifier, PoolUuid, PropChangeAction, RenameAction, ReportType, SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction, StoppedPoolInfo, StoppedPoolsInfo, diff --git a/src/engine/sim_engine/engine.rs b/src/engine/sim_engine/engine.rs index 09c408b044..e6c84678ba 100644 --- a/src/engine/sim_engine/engine.rs +++ b/src/engine/sim_engine/engine.rs @@ -27,9 +27,9 @@ use crate::{ }, types::{ CreateAction, DeleteAction, DevUuid, EncryptionInfo, Features, FilesystemUuid, - LockedPoolsInfo, Name, PoolDevice, PoolDiff, PoolIdentifier, PoolUuid, RenameAction, - ReportType, SetUnlockAction, StartAction, StopAction, StoppedPoolInfo, - StoppedPoolsInfo, StratFilesystemDiff, UdevEngineEvent, UnlockMethod, + IntegrityTagSpec, LockedPoolsInfo, Name, PoolDevice, PoolDiff, PoolIdentifier, + PoolUuid, RenameAction, ReportType, SetUnlockAction, StartAction, StopAction, + StoppedPoolInfo, StoppedPoolsInfo, StratFilesystemDiff, UdevEngineEvent, UnlockMethod, }, StratSigblockVersion, }, @@ -132,7 +132,7 @@ impl Engine for SimEngine { blockdev_paths: &[&Path], encryption_info: Option<&EncryptionInfo>, _: Option, - _: Option, + _: Option, ) -> StratisResult> { validate_name(name)?; let name = Name::new(name.to_owned()); diff --git a/src/engine/strat_engine/backstore/backstore/v2.rs b/src/engine/strat_engine/backstore/backstore/v2.rs index 5be778c441..38bc86d161 100644 --- a/src/engine/strat_engine/backstore/backstore/v2.rs +++ b/src/engine/strat_engine/backstore/backstore/v2.rs @@ -11,9 +11,8 @@ use either::Either; use serde_json::Value; use devicemapper::{ - Bytes, CacheDev, CacheDevTargetTable, CacheTargetParams, DevId, Device, DmDevice, DmFlags, - DmOptions, LinearDev, LinearDevTargetParams, LinearTargetParams, Sectors, TargetLine, - TargetTable, + CacheDev, CacheDevTargetTable, CacheTargetParams, DevId, Device, DmDevice, DmFlags, DmOptions, + LinearDev, LinearDevTargetParams, LinearTargetParams, Sectors, TargetLine, TargetTable, }; use crate::{ @@ -34,8 +33,8 @@ use crate::{ writing::wipe_sectors, }, types::{ - ActionAvailability, BlockDevTier, DevUuid, EncryptionInfo, KeyDescription, PoolUuid, - SizedKeyMemory, UnlockMethod, + ActionAvailability, BlockDevTier, DevUuid, EncryptionInfo, IntegrityTagSpec, + KeyDescription, PoolUuid, SizedKeyMemory, UnlockMethod, }, }, stratis::{StratisError, StratisResult}, @@ -439,7 +438,7 @@ impl Backstore { mda_data_size: MDADataSize, encryption_info: Option<&EncryptionInfo>, integrity_journal_size: Option, - integrity_tag_size: Option, + integrity_tag_size: Option, ) -> StratisResult { let data_tier = DataTier::::new( BlockDevMgr::::initialize(pool_uuid, devices, mda_data_size)?, diff --git a/src/engine/strat_engine/backstore/blockdev/v2.rs b/src/engine/strat_engine/backstore/blockdev/v2.rs index 06c5a745f3..fc52289e95 100644 --- a/src/engine/strat_engine/backstore/blockdev/v2.rs +++ b/src/engine/strat_engine/backstore/blockdev/v2.rs @@ -34,8 +34,8 @@ use crate::{ types::BDAResult, }, types::{ - Compare, DevUuid, DevicePath, Diff, PoolUuid, StateDiff, StratBlockDevDiff, - StratSigblockVersion, + Compare, DevUuid, DevicePath, Diff, IntegrityTagSpec, PoolUuid, StateDiff, + StratBlockDevDiff, StratSigblockVersion, }, }, stratis::{StratisError, StratisResult}, @@ -51,11 +51,17 @@ pub fn integrity_meta_space( total_space: Sectors, journal_size: Sectors, block_size: Bytes, - tag_size: Bytes, + tag_size: IntegrityTagSpec, ) -> Sectors { Bytes(4096).sectors() + journal_size - + Bytes::from(((*total_space.bytes() / *block_size) * *tag_size + 4095) & !4095).sectors() + + Bytes::from( + (((((total_space.bytes() / block_size) * u128::from(tag_size.as_bits())) / 8 + 7) + & !7) + + 4095) + & !4095, + ) + .sectors() } #[derive(Debug)] @@ -221,7 +227,7 @@ impl StratBlockDev { &mut self, integrity_journal_size: Sectors, integrity_block_size: Bytes, - integrity_tag_size: Bytes, + integrity_tag_size: IntegrityTagSpec, ) -> StratisResult { let size = BlockdevSize::new(Self::scan_blkdev_size(self.devnode())?); let metadata_size = self.bda.dev_size(); diff --git a/src/engine/strat_engine/backstore/blockdevmgr.rs b/src/engine/strat_engine/backstore/blockdevmgr.rs index 6a1807886e..a9ab66bd6c 100644 --- a/src/engine/strat_engine/backstore/blockdevmgr.rs +++ b/src/engine/strat_engine/backstore/blockdevmgr.rs @@ -29,7 +29,7 @@ use crate::{ serde_structs::{BaseBlockDevSave, Recordable}, shared::bds_to_bdas, }, - types::{DevUuid, EncryptionInfo, Name, PoolEncryptionInfo, PoolUuid}, + types::{DevUuid, EncryptionInfo, IntegrityTagSpec, Name, PoolEncryptionInfo, PoolUuid}, }, stratis::{StratisError, StratisResult}, }; @@ -248,7 +248,7 @@ impl BlockDevMgr { dev: DevUuid, integrity_journal_size: Sectors, integrity_block_size: Bytes, - integrity_tag_size: Bytes, + integrity_tag_size: IntegrityTagSpec, ) -> StratisResult { let bd = self .block_devs diff --git a/src/engine/strat_engine/backstore/data_tier.rs b/src/engine/strat_engine/backstore/data_tier.rs index 4f74f1d573..1bad1c9d42 100644 --- a/src/engine/strat_engine/backstore/data_tier.rs +++ b/src/engine/strat_engine/backstore/data_tier.rs @@ -27,14 +27,14 @@ use crate::{ }, types::BDARecordResult, }, - types::{BlockDevTier, DevUuid, Name, PoolUuid}, + types::{BlockDevTier, DevUuid, IntegrityTagSpec, Name, PoolUuid}, }, stratis::StratisResult, }; pub const DEFAULT_INTEGRITY_JOURNAL_SIZE: Bytes = Bytes(128 * IEC::Mi as u128); pub const DEFAULT_INTEGRITY_BLOCK_SIZE: Bytes = Bytes(4 * IEC::Ki as u128); -pub const DEFAULT_INTEGRITY_TAG_SIZE: Bytes = Bytes(64u128); +pub const DEFAULT_INTEGRITY_TAG_SIZE: IntegrityTagSpec = IntegrityTagSpec::B512; /// Handles the lowest level, base layer of this tier. #[derive(Debug)] @@ -48,7 +48,7 @@ pub struct DataTier { /// Integrity block size. integrity_block_size: Option, /// Integrity tag size. - integrity_tag_size: Option, + integrity_tag_size: Option, } impl DataTier { @@ -125,7 +125,7 @@ impl DataTier { pub fn new( mut block_mgr: BlockDevMgr, integrity_journal_size: Option, - integrity_tag_size: Option, + integrity_tag_size: Option, ) -> DataTier { let integrity_journal_size = integrity_journal_size.unwrap_or_else(|| DEFAULT_INTEGRITY_JOURNAL_SIZE.sectors()); diff --git a/src/engine/strat_engine/engine.rs b/src/engine/strat_engine/engine.rs index ceb7788df4..fc7961a9ab 100644 --- a/src/engine/strat_engine/engine.rs +++ b/src/engine/strat_engine/engine.rs @@ -37,9 +37,10 @@ use crate::{ SomeLockWriteGuard, Table, }, types::{ - CreateAction, DeleteAction, DevUuid, EncryptionInfo, FilesystemUuid, LockedPoolsInfo, - PoolDiff, PoolIdentifier, RenameAction, ReportType, SetUnlockAction, StartAction, - StopAction, StoppedPoolsInfo, StratFilesystemDiff, UdevEngineEvent, UnlockMethod, + CreateAction, DeleteAction, DevUuid, EncryptionInfo, FilesystemUuid, IntegrityTagSpec, + LockedPoolsInfo, PoolDiff, PoolIdentifier, RenameAction, ReportType, SetUnlockAction, + StartAction, StopAction, StoppedPoolsInfo, StratFilesystemDiff, UdevEngineEvent, + UnlockMethod, }, Engine, Name, Pool, PoolUuid, Report, }, @@ -495,7 +496,7 @@ impl Engine for StratEngine { blockdev_paths: &[&Path], encryption_info: Option<&EncryptionInfo>, journal_size: Option, - tag_size: Option, + tag_size: Option, ) -> StratisResult> { validate_name(name)?; let name = Name::new(name.to_owned()); diff --git a/src/engine/strat_engine/pool/v2.rs b/src/engine/strat_engine/pool/v2.rs index 1b57ccffd0..b6d306a1b1 100644 --- a/src/engine/strat_engine/pool/v2.rs +++ b/src/engine/strat_engine/pool/v2.rs @@ -36,10 +36,10 @@ use crate::{ }, types::{ ActionAvailability, BlockDevTier, Clevis, Compare, CreateAction, DeleteAction, DevUuid, - Diff, EncryptionInfo, FilesystemUuid, GrowAction, Key, KeyDescription, Name, PoolDiff, - PoolEncryptionInfo, PoolUuid, PropChangeAction, RegenAction, RenameAction, - SetCreateAction, SetDeleteAction, SizedKeyMemory, StratFilesystemDiff, StratPoolDiff, - StratSigblockVersion, UnlockMethod, + Diff, EncryptionInfo, FilesystemUuid, GrowAction, IntegrityTagSpec, Key, + KeyDescription, Name, PoolDiff, PoolEncryptionInfo, PoolUuid, PropChangeAction, + RegenAction, RenameAction, SetCreateAction, SetDeleteAction, SizedKeyMemory, + StratFilesystemDiff, StratPoolDiff, StratSigblockVersion, UnlockMethod, }, }, stratis::{StratisError, StratisResult}, @@ -154,7 +154,7 @@ impl StratPool { devices: UnownedDevices, encryption_info: Option<&EncryptionInfo>, journal_size: Option, - tag_size: Option, + tag_size: Option, ) -> StratisResult<(PoolUuid, StratPool)> { let pool_uuid = PoolUuid::new_v4(); diff --git a/src/engine/strat_engine/serde_structs.rs b/src/engine/strat_engine/serde_structs.rs index bb23225b44..b143425a4a 100644 --- a/src/engine/strat_engine/serde_structs.rs +++ b/src/engine/strat_engine/serde_structs.rs @@ -16,7 +16,7 @@ use serde::{Serialize, Serializer}; use devicemapper::{Bytes, Sectors, ThinDevId}; -use crate::engine::types::{DevUuid, Features, FilesystemUuid}; +use crate::engine::types::{DevUuid, Features, FilesystemUuid, IntegrityTagSpec}; const MAXIMUM_STRING_SIZE: usize = 255; @@ -122,7 +122,7 @@ pub struct DataTierSave { #[serde(skip_serializing_if = "Option::is_none")] pub integrity_block_size: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub integrity_tag_size: Option, + pub integrity_tag_size: Option, } #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] diff --git a/src/engine/types/mod.rs b/src/engine/types/mod.rs index 287400c496..0e654ade95 100644 --- a/src/engine/types/mod.rs +++ b/src/engine/types/mod.rs @@ -481,3 +481,43 @@ pub enum StratSigblockVersion { V1 = 1, V2 = 2, } + +/// A way to specify an integrity tag size. It is possible for the specification +/// to be non-numeric but translatable to some number of bits. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub enum IntegrityTagSpec { + B0, + B32, + B512, +} + +impl IntegrityTagSpec { + pub fn as_bits(self) -> u16 { + match self { + IntegrityTagSpec::B0 => 0u16, + IntegrityTagSpec::B32 => 32u16, + IntegrityTagSpec::B512 => 512u16, + } + } +} + +impl TryFrom<&str> for IntegrityTagSpec { + type Error = StratisError; + + fn try_from(s: &str) -> StratisResult { + if let Ok(val) = s.parse::() { + match val { + 0 => Ok(IntegrityTagSpec::B0), + 32 => Ok(IntegrityTagSpec::B32), + 512 => Ok(IntegrityTagSpec::B512), + _ => Err(StratisError::Msg(format!( + "{s} is not a currently supported tag size specification" + ))), + } + } else { + Err(StratisError::Msg(format!( + "{s} is not a currently supported tag size specification" + ))) + } + } +}