diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs index 504a5f34d..a834f6957 100644 --- a/crates/lib/src/install.rs +++ b/crates/lib/src/install.rs @@ -1771,6 +1771,19 @@ fn require_empty_rootdir(rootfs_fd: &Dir) -> Result<()> { if name == LOST_AND_FOUND { continue; } + + // Check if this entry is a directory + let etype = e.file_type()?; + if etype == FileType::dir() { + // Check if this directory is a mount point (separate filesystem) + // If open_dir_noxdev returns None, it means this directory is on a different device + // (i.e., it's a mount point), which is acceptable for to-filesystem installations + if rootfs_fd.open_dir_noxdev(&name)?.is_none() { + tracing::debug!("Skipping mount point: {name}"); + continue; + } + } + // There must be a boot directory (that is empty) if name == BOOT { let mut entries = rootfs_fd.read_dir(BOOT)?; diff --git a/crates/ostree-ext/src/commit.rs b/crates/ostree-ext/src/commit.rs index 31571d1ed..7337a8df4 100644 --- a/crates/ostree-ext/src/commit.rs +++ b/crates/ostree-ext/src/commit.rs @@ -57,10 +57,23 @@ fn clean_subdir(root: &Dir, rootdev: u64) -> Result<()> { tracing::trace!("Skipping entry in foreign dev {path:?}"); continue; } - // Also ignore bind mounts, if we have a new enough kernel with statx() - // that will tell us. + // For mount points (e.g., separate LVM volumes under /var), we need to clean + // their contents but preserve the directory itself. This is critical for cases + // where subdirectories like /var/log or /var/home are separate logical volumes. if root.is_mountpoint(&path)?.unwrap_or_default() { - tracing::trace!("Skipping mount point {path:?}"); + if metadata.is_dir() { + tracing::debug!("Cleaning contents of mount point directory {path:?}"); + // Get the device ID of the mountpoint itself + let mountpoint_dev = metadata.dev(); + // Open the mountpoint directory and clean its contents + if let Some(mountpoint_dir) = root.open_dir_optional(&path)? { + clean_subdir(&mountpoint_dir, mountpoint_dev) + .with_context(|| format!("Cleaning mountpoint {path:?}"))?; + } + // Do not remove the directory itself - it's a mount point + } else { + tracing::trace!("Skipping non-directory mount point {path:?}"); + } continue; } if metadata.is_dir() {