-
Notifications
You must be signed in to change notification settings - Fork 150
WIP: install: Handle mount points in rootfs operations #1727
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1803,6 +1803,54 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> { | |
| Ok(()) | ||
| } | ||
|
|
||
| /// Check if a directory contains only mount points (or is empty), recursively. | ||
| /// Returns true if all entries in the directory tree are either: | ||
| /// - Mount points (on different filesystems) | ||
| /// - Directories that themselves contain only mount points (recursively) | ||
| /// - The lost+found directory | ||
| /// | ||
| /// This handles cases like /var containing /var/lib (not a mount) which contains | ||
| /// /var/lib/containers (a mount point). | ||
| #[context("Checking if directory contains only mount points")] | ||
| fn dir_contains_only_mounts(parent_fd: &Dir, dir_name: &str) -> Result<bool> { | ||
| let Some(dir_fd) = parent_fd.open_dir_noxdev(dir_name)? else { | ||
| // The directory itself is a mount point, which is acceptable | ||
| return Ok(true); | ||
| }; | ||
|
|
||
| for entry in dir_fd.entries()? { | ||
| let entry = DirEntryUtf8::from_cap_std(entry?); | ||
| let entry_name = entry.file_name()?; | ||
|
|
||
| // Skip lost+found | ||
| if entry_name == LOST_AND_FOUND { | ||
| continue; | ||
| } | ||
|
|
||
| let etype = entry.file_type()?; | ||
| if etype == FileType::dir() { | ||
| // If open_dir_noxdev returns None, this is a mount point on a different filesystem | ||
| if dir_fd.open_dir_noxdev(&entry_name)?.is_none() { | ||
| tracing::debug!("Found mount point: {dir_name}/{entry_name}"); | ||
| continue; | ||
| } | ||
|
|
||
| // Not a mount point itself, but check recursively if it contains only mounts | ||
| if dir_contains_only_mounts(&dir_fd, &entry_name)? { | ||
| tracing::debug!("Directory {dir_name}/{entry_name} contains only mount points"); | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| // Found a non-mount, non-directory-of-mounts entry | ||
| tracing::debug!("Found non-mount entry in {dir_name}: {entry_name}"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logs here feel a bit noisy potentially, how about making this
Then I think we probably don't need the logs at all, the error will include the info. |
||
| return Ok(false); | ||
| } | ||
|
|
||
| // All entries are mount points or directories containing only mount points | ||
| Ok(true) | ||
| } | ||
|
|
||
| #[context("Verifying empty rootfs")] | ||
| fn require_empty_rootdir(rootfs_fd: &Dir) -> Result<()> { | ||
| for e in rootfs_fd.entries()? { | ||
|
|
@@ -1811,6 +1859,27 @@ 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
| } | ||
|
|
||
| // If the directory itself is not a mount point, check if it contains only mount points. | ||
| // This handles the case where subdirectories like /var/log, /var/home are separate | ||
| // partitions, creating a /var directory that exists only to hold mount points. | ||
| if dir_contains_only_mounts(rootfs_fd, &name)? { | ||
| tracing::debug!("Skipping directory containing only mount points: {name}"); | ||
| continue; | ||
| } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feels a bit weird to me to fall through here on error instead of just erroring out, see above |
||
| } | ||
|
|
||
| // There must be a boot directory (that is empty) | ||
| if name == BOOT { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we might be able to consolidate this logic with the above? |
||
| let mut entries = rootfs_fd.read_dir(BOOT)?; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could have a unit test for this for the trivial cases at least (no inner mounts). Actually testing the mount case needs an integration test.