Skip to content

Commit 80ea26c

Browse files
committed
upgrade: Add pre-flight disk space check
Extends PR #1245's approach to all bootc upgrade modes that download layers (default, --apply, --download-only). Moves check_disk_space() to deploy.rs for reuse by both install and upgrade operations. This prevents wasted bandwidth and provides immediate feedback when insufficient disk space is available, matching the install behavior. Related: BIFROST-1088 Assisted-by: AI Signed-off-by: Wei Shi <wshi@redhat.com>
1 parent 4ec8a85 commit 80ea26c

2 files changed

Lines changed: 31 additions & 21 deletions

File tree

crates/lib/src/deploy.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use ostree_ext::ostree::Deployment;
2121
use ostree_ext::ostree::{self, Sysroot};
2222
use ostree_ext::sysroot::SysrootLock;
2323
use ostree_ext::tokio_util::spawn_blocking_cancellable_flatten;
24+
use std::os::fd::AsFd;
2425

2526
use crate::progress_jsonl::{Event, ProgressWriter, SubTaskBytes, SubTaskStep};
2627
use crate::spec::ImageReference;
@@ -361,6 +362,31 @@ pub(crate) async fn prune_container_store(sysroot: &Storage) -> Result<()> {
361362
Ok(())
362363
}
363364

365+
/// Verify there is sufficient disk space to pull an image.
366+
///
367+
/// This checks the available space on the filesystem containing the OSTree repository
368+
/// against the number of bytes that need to be fetched for the image.
369+
pub(crate) fn check_disk_space(
370+
repo_fd: impl AsFd,
371+
image_meta: &PreparedImportMeta,
372+
imgref: &ImageReference,
373+
) -> Result<()> {
374+
let stat = rustix::fs::fstatvfs(repo_fd)?;
375+
let bytes_avail: u64 = stat.f_bsize * stat.f_bavail;
376+
tracing::trace!("bytes_avail: {bytes_avail}");
377+
378+
if image_meta.bytes_to_fetch > bytes_avail {
379+
anyhow::bail!(
380+
"Insufficient free space for {image} (available: {bytes_avail} required: {bytes_to_fetch})",
381+
bytes_avail = ostree_ext::glib::format_size(bytes_avail),
382+
bytes_to_fetch = ostree_ext::glib::format_size(image_meta.bytes_to_fetch),
383+
image = imgref.image,
384+
);
385+
}
386+
387+
Ok(())
388+
}
389+
364390
pub(crate) struct PreparedImportMeta {
365391
pub imp: ImageImporter,
366392
pub prep: Box<PreparedImport>,
@@ -658,6 +684,9 @@ pub(crate) async fn pull(
658684
Ok(existing)
659685
}
660686
PreparedPullResult::Ready(prepared_image_meta) => {
687+
// Check disk space before attempting to pull
688+
check_disk_space(repo.dfd_borrow(), &prepared_image_meta, imgref)?;
689+
661690
// Log that we're pulling a new image
662691
const PULLING_NEW_IMAGE_ID: &str = "6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0";
663692
tracing::info!(

crates/lib/src/install.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ use crate::bootc_composefs::{boot::setup_composefs_boot, repo::initialize_compos
191191
use crate::boundimage::{BoundImage, ResolvedBoundImage};
192192
use crate::containerenv::ContainerExecutionInfo;
193193
use crate::deploy::{
194-
MergeState, PreparedImportMeta, PreparedPullResult, prepare_for_pull, pull_from_prepared,
194+
MergeState, PreparedPullResult, prepare_for_pull, pull_from_prepared,
195195
};
196196
use crate::lsm;
197197
use crate::progress_jsonl::ProgressWriter;
@@ -1011,26 +1011,7 @@ async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result
10111011
Ok((storage, has_ostree))
10121012
}
10131013

1014-
fn check_disk_space(
1015-
repo_fd: impl AsFd,
1016-
image_meta: &PreparedImportMeta,
1017-
imgref: &ImageReference,
1018-
) -> Result<()> {
1019-
let stat = rustix::fs::fstatvfs(repo_fd)?;
1020-
let bytes_avail: u64 = stat.f_bsize * stat.f_bavail;
1021-
tracing::trace!("bytes_avail: {bytes_avail}");
1022-
1023-
if image_meta.bytes_to_fetch > bytes_avail {
1024-
anyhow::bail!(
1025-
"Insufficient free space for {image} (available: {bytes_avail} required: {bytes_to_fetch})",
1026-
bytes_avail = ostree_ext::glib::format_size(bytes_avail),
1027-
bytes_to_fetch = ostree_ext::glib::format_size(image_meta.bytes_to_fetch),
1028-
image = imgref.image,
1029-
);
1030-
}
10311014

1032-
Ok(())
1033-
}
10341015

10351016
#[context("Creating ostree deployment")]
10361017
async fn install_container(
@@ -1099,7 +1080,7 @@ async fn install_container(
10991080
let pulled_image = match prepared {
11001081
PreparedPullResult::AlreadyPresent(existing) => existing,
11011082
PreparedPullResult::Ready(image_meta) => {
1102-
check_disk_space(root_setup.physical_root.as_fd(), &image_meta, &spec_imgref)?;
1083+
crate::deploy::check_disk_space(root_setup.physical_root.as_fd(), &image_meta, &spec_imgref)?;
11031084
pull_from_prepared(&spec_imgref, false, ProgressWriter::default(), *image_meta).await?
11041085
}
11051086
};

0 commit comments

Comments
 (0)