Skip to content

Commit 2f51c81

Browse files
storage: Add boot_dir and esp fields
We have a lot of places where we mount the ESP temporarily and a lot of switch cases for Grub's vs SystemdBoot's 'boot' directory. We add a `boot_dir` field in Storage which points to `/sysroot/boot` for systems with Grub as the bootloader and points to the ESP for systems with SystemdBoot as the bootloader. Also we mount the ESP temporarily while creating the storage struct, which cleans up the code quite a bit. Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
1 parent ef52c2c commit 2f51c81

File tree

7 files changed

+101
-132
lines changed

7 files changed

+101
-132
lines changed

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -416,23 +416,8 @@ pub(crate) fn setup_composefs_bls_boot(
416416
let sysroot_parent = get_sysroot_parent_dev(&storage.physical_root)?;
417417
let bootloader = host.require_composefs_booted()?.bootloader.clone();
418418

419-
let current_cfg = match bootloader {
420-
Bootloader::Grub => {
421-
let boot_dir = storage
422-
.physical_root
423-
.open_dir("boot")
424-
.context("Opening boot")?;
425-
426-
get_booted_bls(&boot_dir)?
427-
}
428-
429-
Bootloader::Systemd => {
430-
let esp = get_esp_partition(&sysroot_parent)?.0;
431-
let esp_mnt = mount_esp(&esp)?;
432-
433-
get_booted_bls(&esp_mnt.fd)?
434-
}
435-
};
419+
let boot_dir = storage.require_boot_dir()?;
420+
let current_cfg = get_booted_bls(&boot_dir)?;
436421

437422
let mut cmdline = match current_cfg.cfg_type {
438423
BLSConfigType::NonEFI { options, .. } => {

crates/lib/src/bootc_composefs/delete.rs

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ use composefs_boot::bootloader::{EFI_ADDON_DIR_EXT, EFI_EXT};
77

88
use crate::{
99
bootc_composefs::{
10-
boot::{
11-
find_vmlinuz_initrd_duplicates, get_efi_uuid_source, get_esp_partition,
12-
get_sysroot_parent_dev, mount_esp, BootType, SYSTEMD_UKI_DIR,
13-
},
10+
boot::{find_vmlinuz_initrd_duplicates, get_efi_uuid_source, BootType, SYSTEMD_UKI_DIR},
1411
gc::composefs_gc,
1512
repo::open_composefs_repo,
1613
rollback::{composefs_rollback, rename_exchange_user_cfg},
@@ -215,40 +212,34 @@ fn remove_grub_menucfg_entry(id: &str, boot_dir: &Dir, deleting_staged: bool) ->
215212
#[fn_error_context::context("Deleting boot entries for deployment {}", deployment.deployment.verity)]
216213
fn delete_depl_boot_entries(
217214
deployment: &DeploymentEntry,
218-
physical_root: &Dir,
215+
storage: &Storage,
219216
deleting_staged: bool,
220217
) -> Result<()> {
221-
match deployment.deployment.bootloader {
222-
Bootloader::Grub => {
223-
let boot_dir = physical_root.open_dir("boot").context("Opening boot dir")?;
218+
let boot_dir = storage.require_boot_dir()?;
224219

225-
match deployment.deployment.boot_type {
226-
BootType::Bls => delete_type1_entry(deployment, &boot_dir, deleting_staged),
220+
match deployment.deployment.bootloader {
221+
Bootloader::Grub => match deployment.deployment.boot_type {
222+
BootType::Bls => delete_type1_entry(deployment, boot_dir, deleting_staged),
227223

228-
BootType::Uki => {
229-
let device = get_sysroot_parent_dev(physical_root)?;
230-
let (esp_part, ..) = get_esp_partition(&device)?;
231-
let esp_mount = mount_esp(&esp_part)?;
224+
BootType::Uki => {
225+
let esp = storage
226+
.esp
227+
.as_ref()
228+
.ok_or_else(|| anyhow::anyhow!("ESP not found"))?;
232229

233-
remove_grub_menucfg_entry(
234-
&deployment.deployment.verity,
235-
&boot_dir,
236-
deleting_staged,
237-
)?;
230+
remove_grub_menucfg_entry(
231+
&deployment.deployment.verity,
232+
boot_dir,
233+
deleting_staged,
234+
)?;
238235

239-
delete_uki(&deployment.deployment.verity, &esp_mount.fd)
240-
}
236+
delete_uki(&deployment.deployment.verity, &esp.fd)
241237
}
242-
}
238+
},
243239

244240
Bootloader::Systemd => {
245-
let device = get_sysroot_parent_dev(physical_root)?;
246-
let (esp_part, ..) = get_esp_partition(&device)?;
247-
248-
let esp_mount = mount_esp(&esp_part)?;
249-
250241
// For Systemd UKI as well, we use .conf files
251-
delete_type1_entry(deployment, &esp_mount.fd, deleting_staged)
242+
delete_type1_entry(deployment, boot_dir, deleting_staged)
252243
}
253244
}
254245
}
@@ -362,7 +353,7 @@ pub(crate) async fn delete_composefs_deployment(
362353

363354
tracing::info!("Deleting {kind}deployment '{deployment_id}'");
364355

365-
delete_depl_boot_entries(&depl_to_del, &storage.physical_root, deleting_staged)?;
356+
delete_depl_boot_entries(&depl_to_del, &storage, deleting_staged)?;
366357

367358
composefs_gc(storage, booted_cfs).await?;
368359

crates/lib/src/bootc_composefs/finalize.rs

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use std::path::Path;
22

3-
use crate::bootc_composefs::boot::{
4-
get_esp_partition, get_sysroot_parent_dev, mount_esp, BootType,
5-
};
3+
use crate::bootc_composefs::boot::BootType;
64
use crate::bootc_composefs::rollback::{rename_exchange_bls_entries, rename_exchange_user_cfg};
75
use crate::bootc_composefs::status::get_composefs_status;
86
use crate::composefs_consts::STATE_DIR_ABS;
@@ -86,15 +84,12 @@ pub(crate) async fn composefs_backend_finalize(
8684
// Unmount EROFS
8785
drop(erofs_tmp_mnt);
8886

89-
let sysroot_parent = get_sysroot_parent_dev(&storage.physical_root)?;
90-
// NOTE: Assumption here that ESP will always be present
91-
let (esp_part, ..) = get_esp_partition(&sysroot_parent)?;
87+
let boot_dir = storage.require_boot_dir()?;
9288

93-
let esp_mount = mount_esp(&esp_part)?;
94-
let boot_dir = storage
95-
.physical_root
96-
.open_dir("boot")
97-
.context("Opening boot")?;
89+
let esp_mount = storage
90+
.esp
91+
.as_ref()
92+
.ok_or_else(|| anyhow::anyhow!("ESP not found"))?;
9893

9994
// NOTE: Assuming here we won't have two bootloaders at the same time
10095
match booted_composefs.bootloader {
@@ -103,21 +98,17 @@ pub(crate) async fn composefs_backend_finalize(
10398
let entries_dir = boot_dir.open_dir("loader")?;
10499
rename_exchange_bls_entries(&entries_dir)?;
105100
}
106-
BootType::Uki => finalize_staged_grub_uki(&esp_mount.fd, &boot_dir)?,
101+
BootType::Uki => finalize_staged_grub_uki(&esp_mount.fd, boot_dir)?,
107102
},
108103

109-
Bootloader::Systemd => match staged_composefs.boot_type {
110-
BootType::Bls => {
111-
let entries_dir = esp_mount.fd.open_dir("loader")?;
112-
rename_exchange_bls_entries(&entries_dir)?;
113-
}
114-
BootType::Uki => {
104+
Bootloader::Systemd => {
105+
if matches!(staged_composefs.boot_type, BootType::Uki) {
115106
rename_staged_uki_entries(&esp_mount.fd)?;
116-
117-
let entries_dir = esp_mount.fd.open_dir("loader")?;
118-
rename_exchange_bls_entries(&entries_dir)?;
119107
}
120-
},
108+
109+
let entries_dir = boot_dir.open_dir("loader")?;
110+
rename_exchange_bls_entries(&entries_dir)?;
111+
}
121112
};
122113

123114
Ok(())

crates/lib/src/bootc_composefs/gc.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use composefs::fsverity::{FsVerityHashValue, Sha512HashValue};
1010

1111
use crate::{
1212
bootc_composefs::{
13-
boot::{get_esp_partition, get_sysroot_parent_dev, mount_esp},
1413
delete::{delete_image, delete_staged, delete_state_dir, get_image_objects},
1514
status::{
1615
get_bootloader, get_composefs_status, get_sorted_grub_uki_boot_entries,
@@ -44,28 +43,27 @@ fn list_erofs_images(sysroot: &Dir) -> Result<Vec<String>> {
4443
/// # Returns
4544
/// The fsverity of EROFS images corresponding to boot entries
4645
#[fn_error_context::context("Listing bootloader entries")]
47-
fn list_bootloader_entries(physical_root: &Dir) -> Result<Vec<String>> {
46+
fn list_bootloader_entries(storage: &Storage) -> Result<Vec<String>> {
4847
let bootloader = get_bootloader()?;
48+
let boot_dir = storage.require_boot_dir()?;
4949

5050
let entries = match bootloader {
5151
Bootloader::Grub => {
52-
let boot_dir = physical_root.open_dir("boot").context("Opening boot dir")?;
53-
5452
// Grub entries are always in boot
5553
let grub_dir = boot_dir.open_dir("grub2").context("Opening grub dir")?;
5654

5755
if grub_dir.exists(USER_CFG) {
5856
// Grub UKI
5957
let mut s = String::new();
60-
let boot_entries = get_sorted_grub_uki_boot_entries(&boot_dir, &mut s)?;
58+
let boot_entries = get_sorted_grub_uki_boot_entries(boot_dir, &mut s)?;
6159

6260
boot_entries
6361
.into_iter()
6462
.map(|entry| entry.get_verity())
6563
.collect::<Result<Vec<_>, _>>()?
6664
} else {
6765
// Type1 Entry
68-
let boot_entries = get_sorted_type1_boot_entries(&boot_dir, true)?;
66+
let boot_entries = get_sorted_type1_boot_entries(boot_dir, true)?;
6967

7068
boot_entries
7169
.into_iter()
@@ -75,11 +73,7 @@ fn list_bootloader_entries(physical_root: &Dir) -> Result<Vec<String>> {
7573
}
7674

7775
Bootloader::Systemd => {
78-
let device = get_sysroot_parent_dev(physical_root)?;
79-
let (esp_part, ..) = get_esp_partition(&device)?;
80-
let esp_mount = mount_esp(&esp_part)?;
81-
82-
let boot_entries = get_sorted_type1_boot_entries(&esp_mount.fd, true)?;
76+
let boot_entries = get_sorted_type1_boot_entries(boot_dir, true)?;
8377

8478
boot_entries
8579
.into_iter()
@@ -175,7 +169,7 @@ pub(crate) async fn composefs_gc(storage: &Storage, booted_cfs: &BootedComposefs
175169

176170
let sysroot = &storage.physical_root;
177171

178-
let bootloader_entries = list_bootloader_entries(&storage.physical_root)?;
172+
let bootloader_entries = list_bootloader_entries(&storage)?;
179173
let images = list_erofs_images(&sysroot)?;
180174

181175
// Collect the deployments that have an image but no bootloader entry

crates/lib/src/bootc_composefs/rollback.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ use cap_std_ext::dirext::CapStdExtDirExt;
66
use fn_error_context::context;
77
use rustix::fs::{fsync, renameat_with, AtFlags, RenameFlags};
88

9-
use crate::bootc_composefs::boot::{
10-
get_esp_partition, get_sysroot_parent_dev, mount_esp, type1_entry_conf_file_name, BootType,
11-
};
9+
use crate::bootc_composefs::boot::{type1_entry_conf_file_name, BootType};
1210
use crate::bootc_composefs::status::{get_composefs_status, get_sorted_type1_boot_entries};
1311
use crate::composefs_consts::TYPE1_ENT_PATH_STAGED;
1412
use crate::spec::Bootloader;
@@ -196,31 +194,21 @@ pub(crate) async fn composefs_rollback(
196194
anyhow::bail!("Rollback deployment not a composefs deployment")
197195
};
198196

197+
let boot_dir = storage.require_boot_dir()?;
198+
199199
match &rollback_entry.bootloader {
200-
Bootloader::Grub => {
201-
let boot_dir = storage
202-
.physical_root
203-
.open_dir("boot")
204-
.context("Opening boot dir")?;
205-
206-
match rollback_entry.boot_type {
207-
BootType::Bls => {
208-
rollback_composefs_entries(&boot_dir, rollback_entry.bootloader.clone())?;
209-
}
210-
211-
BootType::Uki => {
212-
rollback_grub_uki_entries(&boot_dir)?;
213-
}
200+
Bootloader::Grub => match rollback_entry.boot_type {
201+
BootType::Bls => {
202+
rollback_composefs_entries(boot_dir, rollback_entry.bootloader.clone())?;
214203
}
215-
}
204+
BootType::Uki => {
205+
rollback_grub_uki_entries(boot_dir)?;
206+
}
207+
},
216208

217209
Bootloader::Systemd => {
218-
let parent = get_sysroot_parent_dev(&storage.physical_root)?;
219-
let (esp_part, ..) = get_esp_partition(&parent)?;
220-
let esp_mount = mount_esp(&esp_part)?;
221-
222210
// We use BLS entries for systemd UKI as well
223-
rollback_composefs_entries(&esp_mount.fd, rollback_entry.bootloader.clone())?;
211+
rollback_composefs_entries(boot_dir, rollback_entry.bootloader.clone())?;
224212
}
225213
}
226214

crates/lib/src/bootc_composefs/status.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ use bootc_kernel_cmdline::utf8::Cmdline;
55
use fn_error_context::context;
66

77
use crate::{
8-
bootc_composefs::boot::{get_esp_partition, get_sysroot_parent_dev, mount_esp, BootType},
8+
bootc_composefs::boot::BootType,
99
composefs_consts::{COMPOSEFS_CMDLINE, ORIGIN_KEY_BOOT_DIGEST, TYPE1_ENT_PATH, USER_CFG},
1010
install::EFI_LOADER_INFO,
1111
parsers::{
1212
bls_config::{parse_bls_config, BLSConfig, BLSConfigType},
1313
grub_menuconfig::{parse_grub_menuentry_file, MenuEntry},
1414
},
1515
spec::{BootEntry, BootOrder, Host, HostSpec, ImageReference, ImageStatus},
16+
store::Storage,
1617
utils::{read_uefi_var, EfiError},
1718
};
1819

@@ -254,17 +255,20 @@ pub(crate) async fn get_composefs_status(
254255
storage: &crate::store::Storage,
255256
booted_cfs: &crate::store::BootedComposefs,
256257
) -> Result<Host> {
257-
composefs_deployment_status_from(&storage.physical_root, booted_cfs.cmdline).await
258+
composefs_deployment_status_from(&storage, booted_cfs.cmdline).await
258259
}
259260

260261
#[context("Getting composefs deployment status")]
261262
pub(crate) async fn composefs_deployment_status_from(
262-
sysroot: &Dir,
263+
storage: &Storage,
263264
cmdline: &ComposefsCmdline,
264265
) -> Result<Host> {
265266
let composefs_digest = &cmdline.digest;
266267

267-
let deployments = sysroot
268+
let boot_dir = storage.require_boot_dir()?;
269+
270+
let deployments = storage
271+
.physical_root
268272
.read_dir(STATE_DIR_RELATIVE)
269273
.with_context(|| format!("Reading sysroot {STATE_DIR_RELATIVE}"))?;
270274

@@ -348,30 +352,10 @@ pub(crate) async fn composefs_deployment_status_from(
348352

349353
let booted = host.require_composefs_booted()?;
350354

351-
let (boot_dir, _temp_guard) = match booted.bootloader {
352-
Bootloader::Grub => (sysroot.open_dir("boot").context("Opening boot dir")?, None),
353-
354-
// TODO: This is redundant as we should already have ESP mounted at `/efi/` accoding to
355-
// spec; currently we do not
356-
//
357-
// See: https://uapi-group.org/specifications/specs/boot_loader_specification/#mount-points
358-
Bootloader::Systemd => {
359-
let parent = get_sysroot_parent_dev(sysroot)?;
360-
let (esp_part, ..) = get_esp_partition(&parent)?;
361-
362-
let esp_mount = mount_esp(&esp_part)?;
363-
364-
let dir = esp_mount.fd.try_clone().context("Cloning fd")?;
365-
let guard = Some(esp_mount);
366-
367-
(dir, guard)
368-
}
369-
};
370-
371355
let is_rollback_queued = match booted.bootloader {
372356
Bootloader::Grub => match boot_type {
373357
BootType::Bls => {
374-
let bls_config = get_sorted_type1_boot_entries(&boot_dir, false)?;
358+
let bls_config = get_sorted_type1_boot_entries(boot_dir, false)?;
375359
let bls_config = bls_config
376360
.first()
377361
.ok_or(anyhow::anyhow!("First boot entry not found"))?;
@@ -392,7 +376,7 @@ pub(crate) async fn composefs_deployment_status_from(
392376
BootType::Uki => {
393377
let mut s = String::new();
394378

395-
!get_sorted_grub_uki_boot_entries(&boot_dir, &mut s)?
379+
!get_sorted_grub_uki_boot_entries(boot_dir, &mut s)?
396380
.first()
397381
.ok_or(anyhow::anyhow!("First boot entry not found"))?
398382
.body
@@ -403,7 +387,7 @@ pub(crate) async fn composefs_deployment_status_from(
403387

404388
// We will have BLS stuff and the UKI stuff in the same DIR
405389
Bootloader::Systemd => {
406-
let bls_config = get_sorted_type1_boot_entries(&boot_dir, false)?;
390+
let bls_config = get_sorted_type1_boot_entries(boot_dir, false)?;
407391
let bls_config = bls_config
408392
.first()
409393
.ok_or(anyhow::anyhow!("First boot entry not found"))?;

0 commit comments

Comments
 (0)