Skip to content

Commit

Permalink
Add infrastructure for allocating from either end of device
Browse files Browse the repository at this point in the history
This commit adds the ability to allocate both data and metadata from
either the front of the back of the device. This will be necessary for
reserving integrity space at the end of the device.
  • Loading branch information
jbaublitz committed Apr 18, 2024
1 parent b708bf0 commit 7d75941
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 7 deletions.
4 changes: 3 additions & 1 deletion src/engine/strat_engine/backstore/blockdev/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ impl InternalBlockDev for StratBlockDev {
}

fn alloc(&mut self, size: Sectors) -> PerDevSegments {
self.used.alloc(size)
self.used.alloc_front(size)
}

fn calc_new_size(&self) -> StratisResult<Option<Sectors>> {
Expand Down Expand Up @@ -571,6 +571,8 @@ impl Recordable<BaseBlockDevSave> for StratBlockDev {
uuid: self.uuid(),
user_info: self.user_info.clone(),
hardware_info: self.hardware_info.clone(),
raid_meta_allocs: Vec::new(),
integrity_meta_allocs: Vec::new(),
}
}
}
Expand Down
20 changes: 19 additions & 1 deletion src/engine/strat_engine/backstore/blockdev/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub struct StratBlockDev {
devnode: DevicePath,
new_size: Option<Sectors>,
blksizes: StratSectorSizes,
raid_meta_allocs: Vec<(Sectors, Sectors)>,
integrity_meta_allocs: Vec<(Sectors, Sectors)>,
}

impl StratBlockDev {
Expand Down Expand Up @@ -114,6 +116,8 @@ impl StratBlockDev {
devnode,
new_size: None,
blksizes,
raid_meta_allocs: Vec::new(),
integrity_meta_allocs: Vec::new(),
})
}

Expand Down Expand Up @@ -159,6 +163,18 @@ impl StratBlockDev {
Ok(blkdev_size(&File::open(physical_path)?)?.sectors())
}

/// Allocate room for metadata from the front of the device.
#[allow(dead_code)]
fn alloc_meta_front(&mut self, size: Sectors) -> PerDevSegments {
self.used.alloc_front(size)
}

/// Allocate room for metadata from the back of the device.
#[allow(dead_code)]
fn alloc_meta_back(&mut self, size: Sectors) -> PerDevSegments {
self.used.alloc_back(size)
}

/// Set the newly detected size of a block device.
pub fn set_new_size(&mut self, new_size: Sectors) {
match self.bda.dev_size().cmp(&BlockdevSize::new(new_size)) {
Expand Down Expand Up @@ -227,7 +243,7 @@ impl InternalBlockDev for StratBlockDev {
}

fn alloc(&mut self, size: Sectors) -> PerDevSegments {
self.used.alloc(size)
self.used.alloc_front(size)
}

fn calc_new_size(&self) -> StratisResult<Option<Sectors>> {
Expand Down Expand Up @@ -352,6 +368,8 @@ impl Recordable<BaseBlockDevSave> for StratBlockDev {
uuid: self.uuid(),
user_info: self.user_info.clone(),
hardware_info: self.hardware_info.clone(),
raid_meta_allocs: self.raid_meta_allocs.clone(),
integrity_meta_allocs: self.integrity_meta_allocs.clone(),
}
}
}
Expand Down
41 changes: 36 additions & 5 deletions src/engine/strat_engine/backstore/range_alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@ impl<'a> Iterator for Iter<'a> {
}
}

impl<'a> DoubleEndedIterator for Iter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.items.next_back()
}
}

#[derive(Debug)]
pub struct RangeAllocator {
segments: PerDevSegments,
Expand Down Expand Up @@ -348,9 +354,9 @@ impl RangeAllocator {
self.segments.sum()
}

/// Attempt to allocate.
/// Attempt to allocate from the front of the device.
/// Returns a PerDevSegments object containing the allocated ranges.
pub fn alloc(&mut self, amount: Sectors) -> PerDevSegments {
pub fn alloc_front(&mut self, amount: Sectors) -> PerDevSegments {
let mut segs = PerDevSegments::new(self.segments.limit());
let mut needed = amount;

Expand All @@ -372,6 +378,31 @@ impl RangeAllocator {
segs
}

/// Attempt to allocate from the back of the device.
/// Returns a PerDevSegments object containing the allocated ranges.
#[allow(dead_code)]
pub fn alloc_back(&mut self, amount: Sectors) -> PerDevSegments {
let mut segs = PerDevSegments::new(self.segments.limit());
let mut needed = amount;

for (&start, &len) in self.segments.complement().iter().rev() {
if needed == Sectors(0) {
break;
}
let to_use = min(needed, len);
let used_range = (start + len - to_use, to_use);
segs.insert(&used_range)
.expect("wholly disjoint from other elements in segs");
needed -= to_use;
}
self.segments = self
.segments
.union(&segs)
.expect("all segments verified to be in available ranges");

segs
}

/// Increase the available size of the RangeAlloc data structure.
///
/// Precondition: new_size > self.limit
Expand Down Expand Up @@ -410,14 +441,14 @@ mod tests {
assert_eq!(allocator.used(), Sectors(100));
assert_eq!(allocator.available(), Sectors(28));

let seg = allocator.alloc(Sectors(50));
let seg = allocator.alloc_front(Sectors(50));
assert_eq!(seg.len(), 2);
assert_eq!(seg.sum(), Sectors(28));
assert_eq!(allocator.used(), Sectors(128));
assert_eq!(allocator.available(), Sectors(0));

let available = allocator.available();
allocator.alloc(available);
allocator.alloc_front(available);
assert_eq!(allocator.available(), Sectors(0));
}

Expand Down Expand Up @@ -490,7 +521,7 @@ mod tests {
fn test_allocator_failures_range_overwrite() {
let mut allocator = RangeAllocator::new(BlockdevSize::new(Sectors(128)), &[]).unwrap();

let seg = allocator.alloc(Sectors(128));
let seg = allocator.alloc_front(Sectors(128));
assert_eq!(allocator.used(), Sectors(128));
assert_eq!(
seg.iter().collect::<Vec<_>>(),
Expand Down
6 changes: 6 additions & 0 deletions src/engine/strat_engine/serde_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ pub struct BaseDevSave {
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct BaseBlockDevSave {
pub uuid: DevUuid,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub raid_meta_allocs: Vec<(Sectors, Sectors)>,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub integrity_meta_allocs: Vec<(Sectors, Sectors)>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(serialize_with = "serialize_option_string")]
pub user_info: Option<String>,
Expand Down

0 comments on commit 7d75941

Please sign in to comment.