Skip to content

Commit 5744139

Browse files
composefs-backend: Implement bootc usr-overlay
Similar to ostree, mount a transient overlayfs on /usr Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent 1a99caf commit 5744139

File tree

4 files changed

+68
-4
lines changed

4 files changed

+68
-4
lines changed

crates/initramfs/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ fn overlay_state(base: impl AsFd, state: impl AsFd, source: &str) -> Result<()>
179179
mount_at_wrapper(fs, base, ".").context("Moving mount")
180180
}
181181

182-
fn overlay_transient(base: impl AsFd) -> Result<()> {
182+
/// Mounts a transient overlayfs with passed in fd as the lowerdir
183+
#[context("Mounting transient overlayfs")]
184+
pub fn overlay_transient(base: impl AsFd) -> Result<()> {
183185
overlay_state(base, prepare_mount(mount_tmpfs()?)?, "transient")
184186
}
185187

crates/lib/src/bootc_composefs/state.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ use std::os::unix::fs::symlink;
22
use std::{fs::create_dir_all, process::Command};
33

44
use anyhow::{Context, Result};
5+
use bootc_initramfs_setup::overlay_transient;
56
use bootc_kernel_cmdline::utf8::Cmdline;
67
use bootc_mount::tempmount::TempMount;
8+
use bootc_mount::{mnt_point_details, run_findmnt};
79
use bootc_utils::CommandRunExt;
810
use camino::Utf8PathBuf;
11+
use cap_std_ext::cap_std::ambient_authority;
12+
use cap_std_ext::cap_std::fs_utf8::Dir;
913
use cap_std_ext::{cap_std, dirext::CapStdExtDirExt};
1014
use composefs::fsverity::{FsVerityHashValue, Sha256HashValue};
1115
use fn_error_context::context;
@@ -163,3 +167,29 @@ pub(crate) fn write_composefs_state(
163167

164168
Ok(())
165169
}
170+
171+
pub(crate) fn composefs_usr_overlay() -> Result<()> {
172+
let findmnt_rs = run_findmnt(&[], None)?;
173+
let root_mnt = findmnt_rs
174+
.filesystems
175+
.iter()
176+
.next()
177+
.ok_or(anyhow::anyhow!("Failed to get root mount"))?;
178+
179+
let usr_mnt = mnt_point_details("/usr", root_mnt);
180+
181+
if let Some(usr_mnt) = usr_mnt {
182+
if usr_mnt.fstype == "overlay" {
183+
println!("A writeable overlayfs is already mounted on /usr");
184+
return Ok(());
185+
}
186+
}
187+
188+
let usr = Dir::open_ambient_dir("/usr", ambient_authority())?;
189+
overlay_transient(usr)?;
190+
191+
println!("A writeable overlayfs is now mounted on /usr");
192+
println!("All changes there will be discarded on reboot.");
193+
194+
Ok(())
195+
}

crates/lib/src/cli.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ use serde::{Deserialize, Serialize};
3131

3232
#[cfg(feature = "composefs-backend")]
3333
use crate::bootc_composefs::{
34-
finalize::composefs_native_finalize, rollback::composefs_rollback, status::composefs_booted,
35-
switch::switch_composefs, update::upgrade_composefs,
34+
finalize::composefs_native_finalize, rollback::composefs_rollback,
35+
state::composefs_usr_overlay, status::composefs_booted, switch::switch_composefs,
36+
update::upgrade_composefs,
3637
};
3738
use crate::deploy::RequiredHostSpec;
3839
use crate::lints;
@@ -1283,7 +1284,17 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
12831284
Ok(())
12841285
}
12851286
Opt::Edit(opts) => edit(opts).await,
1286-
Opt::UsrOverlay => usroverlay().await,
1287+
Opt::UsrOverlay => {
1288+
#[cfg(feature = "composefs-backend")]
1289+
if composefs_booted()?.is_some() {
1290+
composefs_usr_overlay()
1291+
} else {
1292+
usroverlay().await
1293+
}
1294+
1295+
#[cfg(not(feature = "composefs-backend"))]
1296+
usroverlay().await
1297+
}
12871298
Opt::Container(opts) => match opts {
12881299
ContainerOpts::Lint {
12891300
rootfs,

crates/mount/src/mount.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@ pub fn is_source_mounted(path: &str, mounted_fs: &Filesystem) -> bool {
115115
false
116116
}
117117

118+
// Recursively check a given filesystem to see if it contains an already mounted target
119+
// Returns the mount details
120+
pub fn mnt_point_details<'a>(
121+
mount_point: &'a str,
122+
mounted_fs: &'a Filesystem,
123+
) -> Option<&'a Filesystem> {
124+
if mounted_fs.target == mount_point {
125+
return Some(mounted_fs);
126+
}
127+
128+
if let Some(ref children) = mounted_fs.children {
129+
for child in children {
130+
if let Some(details) = mnt_point_details(mount_point, child) {
131+
return Some(details);
132+
}
133+
}
134+
}
135+
136+
None
137+
}
138+
118139
/// Mount a device to the target path.
119140
pub fn mount(dev: &str, target: &Utf8Path) -> Result<()> {
120141
Command::new("mount")

0 commit comments

Comments
 (0)