Use less memory when decompressing images for install

1. Delete source image before decompressing temporary file
2. Decompress the images serially instead of spawning a thread for each
   one.
This commit is contained in:
Bruce Leidl 2022-05-27 18:06:52 -04:00
parent 0832ddfa9f
commit 3dbfda2c40
6 changed files with 33 additions and 16 deletions

View File

@ -20,7 +20,7 @@ pub fn live_rootfs() -> Result<()> {
}
pub fn live_setup() -> Result<()> {
decompress_images()?;
decompress_images(true)?;
info!("Starting live setup");
let live = Installer::new_livesetup();
live.run()
@ -131,14 +131,21 @@ fn find_rootfs_image() -> Result<ResourceImage> {
bail!("unable to find rootfs resource image in {}", IMAGE_DIRECTORY)
}
fn decompress_images() -> Result<()> {
fn decompress_images(sync: bool) -> Result<()> {
info!("Decompressing images");
let mut threads = Vec::new();
util::read_directory("/run/citadel/images", |dent| {
if dent.path().extension() == Some(OsStr::new("img")) {
if let Ok(image) = ResourceImage::from_path(&dent.path()) {
if image.is_compressed() {
threads.push(decompress_one_image(image));
if sync {
if let Err(err) = decompress_one_image_sync(image) {
warn!("Error: {}", err);
}
} else {
threads.push(decompress_one_image(image));
}
}
}
}
@ -146,22 +153,28 @@ fn decompress_images() -> Result<()> {
})?;
for t in threads {
t.join().unwrap()?;
if let Err(err) = t.join().unwrap() {
warn!("Error: {}", err);
}
}
info!("Finished decompressing images");
Ok(())
}
fn decompress_one_image(image: ResourceImage) -> JoinHandle<Result<()>> {
thread::spawn(move || {
fn decompress_one_image_sync(image: ResourceImage) -> Result<()> {
let start = Instant::now();
info!("Decompressing {}", image.path().display());
image.decompress()?;
image.decompress(true)
.map_err(|e| format_err!("Failed to decompress image file {}: {}", image.path().display(), e))?;
cmd!("/usr/bin/du", "-h {}", image.path().display())?;
info!("Decompress {:?} finished in {} seconds",
image.path().file_name().unwrap(),
start.elapsed().as_secs());
Ok(())
}
fn decompress_one_image(image: ResourceImage) -> JoinHandle<Result<()>> {
thread::spawn(move || {
decompress_one_image_sync(image)
})
}

View File

@ -23,7 +23,7 @@ pub fn setup_rootfs_resource(rootfs: &ResourceImage) -> Result<()> {
fn setup_resource_unverified(img: &ResourceImage) -> Result<()> {
if img.is_compressed() {
img.decompress()?;
img.decompress(false)?;
}
let loopdev = LoopDevice::create(img.path(), Some(4096), true)?;
info!("Loop device created: {}", loopdev);

View File

@ -275,7 +275,7 @@ fn decompress(arg_matches: &ArgMatches) -> Result<()> {
if !img.is_compressed() {
info!("Image is not compressed, not decompressing.");
} else {
img.decompress()?;
img.decompress(false)?;
}
Ok(())
}

View File

@ -122,7 +122,7 @@ fn install_image(path: &Path, flags: u32) -> Result<()> {
// dmverity hash tree.
fn prepare_image(image: &ResourceImage, flags: u32) -> Result<()> {
if image.is_compressed() {
image.decompress()?;
image.decompress(false)?;
}
if flags & FLAG_SKIP_SHA == 0 {

View File

@ -54,7 +54,7 @@ impl Exec {
.map_err(context!("failed to execute command {}", self.cmd_name))?;
for line in BufReader::new(result.stderr.as_slice()).lines() {
verbose!(" {}", line.unwrap());
warn!(" {}", line.unwrap());
}
self.check_cmd_status(result.status)
}

View File

@ -138,7 +138,7 @@ impl ResourceImage {
self.header.has_flag(ImageHeader::FLAG_HASH_TREE)
}
pub fn decompress(&self) -> Result<()> {
pub fn decompress(&self, early_remove: bool) -> Result<()> {
if !self.is_compressed() {
return Ok(())
}
@ -154,6 +154,10 @@ impl ResourceImage {
io::copy(&mut reader, &mut out)
.map_err(context!("error copying image file {:?} to temporary file", self.path()))?;
if early_remove {
util::remove_file(self.path())?;
}
util::xz_decompress(xzfile)?;
let tmpfile = self.path.with_extension("tmp");
util::rename(&tmpfile, self.path())?;
@ -218,7 +222,7 @@ impl ResourceImage {
return Ok(())
}
if self.is_compressed() {
self.decompress()?;
self.decompress(false)?;
}
info!("Generating dm-verity hash tree for image {}", self.path.display());
let verity = self.verity()?;
@ -239,7 +243,7 @@ impl ResourceImage {
pub fn generate_shasum(&self) -> Result<String> {
if self.is_compressed() {
self.decompress()?;
self.decompress(false)?;
}
info!("Calculating sha256 of image");
let output = util::exec_cmdline_pipe_input("sha256sum", "-", self.path(), util::FileRange::Range{offset: 4096, len: self.metainfo().nblocks() * 4096})
@ -256,7 +260,7 @@ impl ResourceImage {
info!("loop mounting image to {} (noverity)", self.mount_path().display());
if self.is_compressed() {
self.decompress()?;
self.decompress(false)?;
}
let loopdev = LoopDevice::create(self.path(), Some(4096), true)?;