Fix broken realmfs autoresize

This commit is contained in:
Bruce Leidl 2024-09-06 10:02:23 -04:00
parent 2dc8bf2922
commit 24f786cf75
2 changed files with 34 additions and 30 deletions

View File

@ -23,8 +23,8 @@ impl ResizeSize {
pub fn gigs(n: usize) -> Self {
ResizeSize(BLOCKS_PER_GIG * n)
}
pub fn megs(n: usize) -> Self {
ResizeSize(BLOCKS_PER_MEG * n)
}
@ -45,8 +45,8 @@ impl ResizeSize {
self.0 / BLOCKS_PER_MEG
}
/// If the RealmFS needs to be resized to a larger size, returns the
/// recommended size.
/// If the RealmFS has less than `AUTO_RESIZE_MINIMUM_FREE` blocks free then choose a new
/// size to resize the filesystem to and return it. Otherwise, return `None`
pub fn auto_resize_size(realmfs: &RealmFS) -> Option<ResizeSize> {
let sb = match Superblock::load(realmfs.path(), 4096) {
Ok(sb) => sb,
@ -56,22 +56,37 @@ impl ResizeSize {
},
};
sb.free_block_count();
let free_blocks = sb.free_block_count() as usize;
if free_blocks < AUTO_RESIZE_MINIMUM_FREE.nblocks() {
let metainfo_nblocks = realmfs.metainfo().nblocks() + 1;
let increase_multiple = metainfo_nblocks / AUTO_RESIZE_INCREASE_SIZE.nblocks();
let grow_size = (increase_multiple + 1) * AUTO_RESIZE_INCREASE_SIZE.nblocks();
let mask = grow_size - 1;
let grow_blocks = (free_blocks + mask) & !mask;
Some(ResizeSize::blocks(grow_blocks))
if free_blocks >= AUTO_RESIZE_MINIMUM_FREE.nblocks() {
return None;
}
let metainfo_nblocks = realmfs.metainfo().nblocks();
if metainfo_nblocks >= AUTO_RESIZE_INCREASE_SIZE.nblocks() {
return Some(ResizeSize::blocks(metainfo_nblocks + AUTO_RESIZE_INCREASE_SIZE.nblocks()))
}
// If current size is under 4GB (AUTO_RESIZE_INCREASE_SIZE) and raising size to 4GB will create more than the
// minimum free space (1GB) then just do that.
if free_blocks + (AUTO_RESIZE_INCREASE_SIZE.nblocks() - metainfo_nblocks) >= AUTO_RESIZE_MINIMUM_FREE.nblocks() {
Some(AUTO_RESIZE_INCREASE_SIZE)
} else {
None
// Otherwise for original size under 4GB, since raising to 4GB is not enough,
// raise size to 8GB
Some(ResizeSize::blocks(AUTO_RESIZE_INCREASE_SIZE.nblocks() * 2))
}
}
}
const SUPERBLOCK_SIZE: usize = 1024;
/// An EXT4 superblock structure.
///
/// A class for reading the first superblock from an EXT4 filesystem
/// and parsing the Free Block Count field. No other fields are parsed
/// since this is the only information needed for the resize operation.
///
pub struct Superblock([u8; SUPERBLOCK_SIZE]);
impl Superblock {

View File

@ -76,8 +76,6 @@ impl <'a> Update<'a> {
}
self.realmfs.copy_image_file(self.target())?;
self.truncate_verity()?;
self.resize_image_file()?;
Ok(())
}
@ -115,9 +113,8 @@ impl <'a> Update<'a> {
}
// Return size of image file in blocks based on metainfo `nblocks` field.
// Include header block in count so add one block
fn metainfo_nblock_size(&self) -> usize {
self.realmfs.metainfo().nblocks() + 1
self.realmfs.metainfo().nblocks()
}
fn unmount_update_image(&mut self) {
@ -159,7 +156,8 @@ impl <'a> Update<'a> {
}
fn set_target_len(&self, nblocks: usize) -> Result<()> {
let len = (nblocks * BLOCK_SIZE) as u64;
// add one block for header block
let len = ((nblocks + 1) * BLOCK_SIZE) as u64;
let f = fs::OpenOptions::new()
.write(true)
.open(&self.target)
@ -176,7 +174,7 @@ impl <'a> Update<'a> {
if self.realmfs.header().has_flag(ImageHeader::FLAG_HASH_TREE) {
self.set_target_len(metainfo_nblocks)?;
} else if file_nblocks > metainfo_nblocks {
} else if file_nblocks > (metainfo_nblocks + 1) {
warn!("RealmFS image size was greater than length indicated by metainfo.nblocks but FLAG_HASH_TREE not set");
}
Ok(())
@ -185,7 +183,7 @@ impl <'a> Update<'a> {
// If resize was requested, adjust size of update copy of image file.
fn resize_image_file(&self) -> Result<()> {
let nblocks = match self.resize {
Some(rs) => rs.nblocks() + 1,
Some(rs) => rs.nblocks(),
None => return Ok(()),
};
@ -224,7 +222,7 @@ impl <'a> Update<'a> {
fn seal(&mut self) -> Result<()> {
let nblocks = match self.resize {
Some(rs) => rs.nblocks(),
None => self.metainfo_nblock_size() - 1,
None => self.metainfo_nblock_size(),
};
let salt = hex::encode(randombytes(32));
@ -232,20 +230,11 @@ impl <'a> Update<'a> {
.map_err(context!("failed to create verity context for realmfs update image {:?}", self.target()))?;
let output = verity.generate_image_hashtree_with_salt(&salt, nblocks)
.map_err(context!("failed to generate dm-verity hashtree for realmfs update image {:?}", self.target()))?;
// XXX passes metainfo for nblocks
//let output = Verity::new(&self.target).generate_image_hashtree_with_salt(&self.realmfs.metainfo(), &salt)?;
let root_hash = output.root_hash()
.ok_or_else(|| format_err!("no root hash returned from verity format operation"))?;
info!("root hash is {}", output.root_hash().unwrap());
/*
let nblocks = match self.resize {
Some(rs) => rs.nblocks(),
None => self.metainfo_nblock_size() - 1,
};
*/
info!("Signing new image with user realmfs keys");
let metainfo_bytes = RealmFS::generate_metainfo(self.realmfs.name(), nblocks, salt.as_str(), root_hash);
let keys = self.realmfs.sealing_keys().expect("No sealing keys");