Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions crates/lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Offhand this seems sane to me

// 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)?;
Expand Down
19 changes: 16 additions & 3 deletions crates/ostree-ext/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down