From 59f77ae0241445854db7aa94d3876408b7d2bac4 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Thu, 7 Nov 2024 10:03:58 -0500 Subject: [PATCH] Record integrity parameters in metadata --- .../strat_engine/backstore/backstore/v2.rs | 18 ++++--- .../strat_engine/backstore/blockdev/mod.rs | 9 +++- .../strat_engine/backstore/blockdev/v1.rs | 4 +- .../strat_engine/backstore/blockdev/v2.rs | 38 ++++++++----- .../strat_engine/backstore/blockdevmgr.rs | 14 ++++- .../strat_engine/backstore/data_tier.rs | 54 ++++++++++++++++--- src/engine/strat_engine/pool/v2.rs | 10 +++- src/engine/strat_engine/serde_structs.rs | 5 +- 8 files changed, 116 insertions(+), 36 deletions(-) diff --git a/src/engine/strat_engine/backstore/backstore/v2.rs b/src/engine/strat_engine/backstore/backstore/v2.rs index 56e970437c..99f54e0f71 100644 --- a/src/engine/strat_engine/backstore/backstore/v2.rs +++ b/src/engine/strat_engine/backstore/backstore/v2.rs @@ -11,8 +11,9 @@ use either::Either; use serde_json::Value; use devicemapper::{ - CacheDev, CacheDevTargetTable, CacheTargetParams, DevId, Device, DmDevice, DmFlags, DmOptions, - LinearDev, LinearDevTargetParams, LinearTargetParams, Sectors, TargetLine, TargetTable, + Bytes, CacheDev, CacheDevTargetTable, CacheTargetParams, DevId, Device, DmDevice, DmFlags, + DmOptions, LinearDev, LinearDevTargetParams, LinearTargetParams, Sectors, TargetLine, + TargetTable, }; use crate::{ @@ -437,12 +438,15 @@ impl Backstore { devices: UnownedDevices, mda_data_size: MDADataSize, encryption_info: Option<&EncryptionInfo>, + integrity_journal_size: Option, + integrity_tag_size: Option, ) -> StratisResult { - let data_tier = DataTier::::new(BlockDevMgr::::initialize( - pool_uuid, - devices, - mda_data_size, - )?); + let data_tier = DataTier::::new( + BlockDevMgr::::initialize(pool_uuid, devices, mda_data_size)?, + integrity_journal_size, + None, + integrity_tag_size, + ); let mut backstore = Backstore { data_tier, diff --git a/src/engine/strat_engine/backstore/blockdev/mod.rs b/src/engine/strat_engine/backstore/blockdev/mod.rs index 986a2a8a2b..565af94310 100644 --- a/src/engine/strat_engine/backstore/blockdev/mod.rs +++ b/src/engine/strat_engine/backstore/blockdev/mod.rs @@ -6,7 +6,7 @@ use std::{fmt, path::Path}; use chrono::{DateTime, Utc}; -use devicemapper::{Device, Sectors}; +use devicemapper::{Bytes, Device, Sectors}; use crate::{ engine::{ @@ -104,7 +104,12 @@ pub trait InternalBlockDev { /// an exclusive lock on the pool and therefore the thin pool cannot be /// extended to use the larger or unencrypted block device size until the /// transaction has been completed successfully. - fn grow(&mut self) -> StratisResult; + fn grow( + &mut self, + integrity_journal_size: Sectors, + integrity_block_size: Bytes, + integrity_tag_size: Bytes, + ) -> StratisResult; /// Load the pool-level metadata for the given block device. fn load_state(&self) -> StratisResult, &DateTime)>>; diff --git a/src/engine/strat_engine/backstore/blockdev/v1.rs b/src/engine/strat_engine/backstore/blockdev/v1.rs index ffbd71dcc6..3c04900240 100644 --- a/src/engine/strat_engine/backstore/blockdev/v1.rs +++ b/src/engine/strat_engine/backstore/blockdev/v1.rs @@ -14,7 +14,7 @@ use std::{ use chrono::{DateTime, Utc}; use serde_json::Value; -use devicemapper::{Device, Sectors}; +use devicemapper::{Bytes, Device, Sectors}; use crate::{ engine::{ @@ -401,7 +401,7 @@ impl InternalBlockDev for StratBlockDev { } } - fn grow(&mut self) -> StratisResult { + fn grow(&mut self, _: Sectors, _: Bytes, _: Bytes) -> StratisResult { /// Precondition: size > h.blkdev_size fn needs_rollback(bd: &mut StratBlockDev, size: BlockdevSize) -> StratisResult<()> { let mut f = OpenOptions::new() diff --git a/src/engine/strat_engine/backstore/blockdev/v2.rs b/src/engine/strat_engine/backstore/blockdev/v2.rs index 985c110fe6..b657f8229a 100644 --- a/src/engine/strat_engine/backstore/blockdev/v2.rs +++ b/src/engine/strat_engine/backstore/blockdev/v2.rs @@ -14,7 +14,7 @@ use std::{ use chrono::{DateTime, Utc}; use serde_json::Value; -use devicemapper::{Bytes, Device, Sectors, IEC}; +use devicemapper::{Bytes, Device, Sectors}; use crate::{ engine::{ @@ -43,14 +43,19 @@ use crate::{ /// Return the amount of space required for integrity for a device of the given size. /// -/// This is a slight overestimation for the sake of simplicity. Because it uses the whole disk +/// This default is a slight overestimation for the sake of simplicity. Because it uses the whole disk /// size, once the integrity metadata size is calculated, the remaining data size is now smaller /// than the metadata region could support for integrity. /// The result is divisible by 8 sectors. -pub fn integrity_meta_space(total_space: Sectors) -> Sectors { +pub fn integrity_meta_space( + total_space: Sectors, + journal_size: Sectors, + block_size: Bytes, + tag_size: Bytes, +) -> Sectors { Bytes(4096).sectors() - + Bytes::from(64 * IEC::Mi).sectors() - + Bytes::from((*total_space * 32u64 + 4095) & !4095).sectors() + + journal_size + + Bytes::from(((*total_space.bytes() / *block_size) * *tag_size + 4095) & !4095).sectors() } #[derive(Debug)] @@ -269,7 +274,12 @@ impl InternalBlockDev for StratBlockDev { } } - fn grow(&mut self) -> StratisResult { + fn grow( + &mut self, + integrity_journal_size: Sectors, + integrity_block_size: Bytes, + integrity_tag_size: Bytes, + ) -> StratisResult { let size = BlockdevSize::new(Self::scan_blkdev_size(self.devnode())?); let metadata_size = self.bda.dev_size(); match size.cmp(&metadata_size) { @@ -296,12 +306,16 @@ impl InternalBlockDev for StratBlockDev { self.bda.header = h; self.used.increase_size(size.sectors()); - let integrity_grow = integrity_meta_space(size.sectors()) - - self - .integrity_meta_allocs - .iter() - .map(|(_, len)| *len) - .sum::(); + let integrity_grow = integrity_meta_space( + size.sectors(), + integrity_journal_size, + integrity_block_size, + integrity_tag_size, + ) - self + .integrity_meta_allocs + .iter() + .map(|(_, len)| *len) + .sum::(); self.alloc_int_meta_back(integrity_grow); Ok(true) diff --git a/src/engine/strat_engine/backstore/blockdevmgr.rs b/src/engine/strat_engine/backstore/blockdevmgr.rs index 04525081c3..5d349bec78 100644 --- a/src/engine/strat_engine/backstore/blockdevmgr.rs +++ b/src/engine/strat_engine/backstore/blockdevmgr.rs @@ -467,13 +467,23 @@ where self.block_devs.iter().map(|bd| bd.metadata_size()).sum() } - pub fn grow(&mut self, dev: DevUuid) -> StratisResult { + pub fn grow( + &mut self, + dev: DevUuid, + integrity_journal_size: Sectors, + integrity_block_size: Bytes, + integrity_tag_size: Bytes, + ) -> StratisResult { let bd = self .block_devs .iter_mut() .find(|bd| bd.uuid() == dev) .ok_or_else(|| StratisError::Msg(format!("Block device with UUID {dev} not found")))?; - bd.grow() + bd.grow( + integrity_journal_size, + integrity_block_size, + integrity_tag_size, + ) } /// Tear down devicemapper devices for the block devices in this BlockDevMgr. diff --git a/src/engine/strat_engine/backstore/data_tier.rs b/src/engine/strat_engine/backstore/data_tier.rs index 04fd6fc9b5..a5d122f124 100644 --- a/src/engine/strat_engine/backstore/data_tier.rs +++ b/src/engine/strat_engine/backstore/data_tier.rs @@ -7,7 +7,7 @@ #[cfg(test)] use std::collections::HashSet; -use devicemapper::Sectors; +use devicemapper::{Bytes, Sectors, IEC}; use crate::{ engine::{ @@ -32,6 +32,10 @@ use crate::{ stratis::StratisResult, }; +const DEFAULT_INTEGRITY_JOURNAL_SIZE: Bytes = Bytes(128 * IEC::Mi as u128); +const DEFAULT_INTEGRITY_BLOCK_SIZE: Bytes = Bytes(4 * IEC::Ki as u128); +const DEFAULT_INTEGRITY_TAG_SIZE: Bytes = Bytes(64u128); + /// Handles the lowest level, base layer of this tier. #[derive(Debug)] pub struct DataTier { @@ -39,6 +43,12 @@ pub struct DataTier { pub(super) block_mgr: BlockDevMgr, /// The list of segments granted by block_mgr and used by dm_device pub(super) segments: AllocatedAbove, + /// Integrity journal size. + integrity_journal_size: Sectors, + /// Integrity tag size. + integrity_tag_size: Bytes, + /// Integrity block size. + integrity_block_size: Bytes, } impl DataTier { @@ -105,16 +115,33 @@ impl DataTier { /// Initially 0 segments are allocated. /// /// WARNING: metadata changing event - pub fn new(mut block_mgr: BlockDevMgr) -> DataTier { + pub fn new( + mut block_mgr: BlockDevMgr, + integrity_journal_size: Option, + integrity_block_size: Option, + integrity_tag_size: Option, + ) -> DataTier { + let integrity_journal_size = + integrity_journal_size.unwrap_or_else(|| DEFAULT_INTEGRITY_JOURNAL_SIZE.sectors()); + let integrity_block_size = integrity_block_size.unwrap_or(DEFAULT_INTEGRITY_BLOCK_SIZE); + let integrity_tag_size = integrity_tag_size.unwrap_or(DEFAULT_INTEGRITY_TAG_SIZE); for (_, bd) in block_mgr.blockdevs_mut() { // NOTE: over-allocates integrity metadata slightly. Some of the // total size of the device will not make use of the integrity // metadata. - bd.alloc_int_meta_back(integrity_meta_space(bd.total_size().sectors())); + bd.alloc_int_meta_back(integrity_meta_space( + bd.total_size().sectors(), + integrity_journal_size, + integrity_block_size, + integrity_tag_size, + )); } DataTier { block_mgr, segments: AllocatedAbove { inner: vec![] }, + integrity_journal_size, + integrity_block_size, + integrity_tag_size, } } @@ -142,10 +169,10 @@ impl DataTier { assert_eq!(bds.len(), uuids.len()); for bd in bds { bd.alloc_int_meta_back(integrity_meta_space( - // NOTE: Subtracting metadata size works here because the only metadata currently - // recorded in a newly created block device is the BDA. If this becomes untrue in - // the future, this code will no longer work. - bd.total_size().sectors() - bd.metadata_size(), + bd.total_size().sectors(), + self.integrity_journal_size, + self.integrity_block_size, + self.integrity_tag_size, )); } Ok(uuids) @@ -207,6 +234,9 @@ where Ok(DataTier { block_mgr, segments, + integrity_journal_size: data_tier_save.integrity_journal_size, + integrity_block_size: data_tier_save.integrity_block_size, + integrity_tag_size: data_tier_save.integrity_tag_size, }) } @@ -266,7 +296,12 @@ where } pub fn grow(&mut self, dev: DevUuid) -> StratisResult { - self.block_mgr.grow(dev) + self.block_mgr.grow( + dev, + self.integrity_journal_size, + self.integrity_block_size, + self.integrity_tag_size, + ) } /// Return the partition of the block devs that are in use and those @@ -301,6 +336,9 @@ where allocs: vec![self.segments.record()], devs: self.block_mgr.record(), }, + integrity_journal_size: self.integrity_journal_size, + integrity_block_size: self.integrity_block_size, + integrity_tag_size: self.integrity_tag_size, } } } diff --git a/src/engine/strat_engine/pool/v2.rs b/src/engine/strat_engine/pool/v2.rs index d0990011b4..288cd85ae1 100644 --- a/src/engine/strat_engine/pool/v2.rs +++ b/src/engine/strat_engine/pool/v2.rs @@ -159,8 +159,14 @@ impl StratPool { // FIXME: Initializing with the minimum MDA size is not necessarily // enough. If there are enough devices specified, more space will be // required. - let mut backstore = - Backstore::initialize(pool_uuid, devices, MDADataSize::default(), encryption_info)?; + let mut backstore = Backstore::initialize( + pool_uuid, + devices, + MDADataSize::default(), + encryption_info, + None, + None, + )?; let thinpool = ThinPool::::new( pool_uuid, diff --git a/src/engine/strat_engine/serde_structs.rs b/src/engine/strat_engine/serde_structs.rs index a9c907139d..0e1ddf7b74 100644 --- a/src/engine/strat_engine/serde_structs.rs +++ b/src/engine/strat_engine/serde_structs.rs @@ -14,7 +14,7 @@ use serde::{Serialize, Serializer}; -use devicemapper::{Sectors, ThinDevId}; +use devicemapper::{Bytes, Sectors, ThinDevId}; use crate::engine::types::{DevUuid, Features, FilesystemUuid}; @@ -117,6 +117,9 @@ pub struct BackstoreSave { #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct DataTierSave { pub blockdev: BlockDevSave, + pub integrity_journal_size: Sectors, + pub integrity_block_size: Bytes, + pub integrity_tag_size: Bytes, } #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]