Work on making partitions start-end calculate properly. Specifically 2mb at start and -33 sectors GPT reserved at the end.

This commit is contained in:
2026-09-28 00:13:12 +02:00
parent fa5c3d3aec
commit 3b086605cf
2 changed files with 108 additions and 43 deletions
+75 -21
View File
@@ -20,7 +20,7 @@
use crate::kira_size::KiraSize; use crate::kira_size::KiraSize;
use log; use log;
use std::{collections::HashMap}; use std::collections::HashMap;
/// ///
/// size - device size in bytes /// size - device size in bytes
/// sector size - default 4096 /// sector size - default 4096
@@ -124,13 +124,18 @@ pub struct BcachefsProp {
impl BcachefsProp { impl BcachefsProp {
pub fn new(password: Option<String>, comp_alg: Option<String>) -> Self { pub fn new(password: Option<String>, comp_alg: Option<String>) -> Self {
Self { password:password, comp_alg: comp_alg } Self {
password: password,
comp_alg: comp_alg,
}
} }
pub fn default() -> Self { pub fn default() -> Self {
Self { password: None, comp_alg: None } Self {
password: None,
comp_alg: None,
}
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@@ -208,7 +213,7 @@ impl FSType {
pub enum PartRole { pub enum PartRole {
EFI, EFI,
ROOT, ROOT,
SWAP SWAP,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@@ -230,6 +235,22 @@ impl std::fmt::Display for PartInfo {
} }
impl PartInfo { impl PartInfo {
///
/// calculate par end byte as 0 starting bytes index (for parted and such)
///
pub fn part_end(&self) -> KiraSize {
// important to shift here by 1 because disk index is starting from 0, and part end pointing to last byte of the partition.
(self.start + self.size) - KiraSize::new_b(1)
}
///
/// Returns zero based byte index of start of next (right after this one) partition
///
pub fn next_part_start(&self) -> KiraSize {
// important to shift here by 1 because disk index is starting from 0, and part end pointing to last byte of the partition.
self.start + self.size
}
pub fn from_hash_map(data: &HashMap<String, String>) -> Option<Self> { pub fn from_hash_map(data: &HashMap<String, String>) -> Option<Self> {
Some(Self { Some(Self {
name: data.get("NAME")?.clone(), name: data.get("NAME")?.clone(),
@@ -250,7 +271,9 @@ impl PartInfo {
} }
pub fn partlabel_dev(&self) -> Option<String> { pub fn partlabel_dev(&self) -> Option<String> {
self.gpt_label.as_ref().and_then(|l| Some(format!("/dev/disk/by-partlabel/{}", l))) self.gpt_label
.as_ref()
.and_then(|l| Some(format!("/dev/disk/by-partlabel/{}", l)))
} }
} }
@@ -329,7 +352,7 @@ pub fn align_part(size: u64, start: u64, align: u64) -> Option<(u64, u64, u64)>
// decreasing end if not align // decreasing end if not align
let part_end = align_start + size; let part_end = align_start + size;
let end_mod = part_end % align; let end_mod = part_end % align;
log::debug!("part_end: {} end_mod: {}", part_end, end_mod);
let align_end = part_end - end_mod - 1; let align_end = part_end - end_mod - 1;
let align_size = align_end - align_start + 1; let align_size = align_end - align_start + 1;
@@ -342,7 +365,13 @@ pub fn align_part(size: u64, start: u64, align: u64) -> Option<(u64, u64, u64)>
); );
return None; return None;
} }
log::debug!(
"align_size: {}, align_start:{}, align_end: {} end_mod: {}",
align_size,
align_start,
align_end,
end_mod
);
Some((align_size, align_start, align_end)) Some((align_size, align_start, align_end))
} }
@@ -353,10 +382,16 @@ pub struct PartLayout {
pub part_list: Vec<PartInfo>, pub part_list: Vec<PartInfo>,
} }
///
/// GPT requires 33x512 sectors at the very end of the disk (16,896 bytes = 16.5 KiB):
/// 32 sectors — backup Partition Entry Array (128 entries × 128 bytes = 16,384 bytes)
/// 1 sector — backup GPT header
impl PartLayout { impl PartLayout {
pub fn new(dev: BlkDev) -> Self { pub fn new(dev: BlkDev) -> Self {
// 16896 - reserved space at the dev end for gpt
let usable_space = dev.size - KiraSize::new_b(16896);
Self { Self {
empty_space: dev.size, empty_space: usable_space,
dev: dev, dev: dev,
part_list: Vec::new(), part_list: Vec::new(),
} }
@@ -374,11 +409,11 @@ impl PartLayout {
}) })
} }
pub fn new_table(mut self) -> Self { // pub fn new_table(mut self) -> Self {
self.empty_space = self.dev.size; // self.empty_space = self.dev.size;
self.part_list = Vec::new(); // self.part_list = Vec::new();
self // self
} // }
pub fn add_part( pub fn add_part(
mut self, mut self,
@@ -390,19 +425,29 @@ impl PartLayout {
role: Option<PartRole>, role: Option<PartRole>,
) -> Self { ) -> Self {
let part_start = if self.part_list.is_empty() { let part_start = if self.part_list.is_empty() {
// need to substract 2 mb offset from disk start.
self.empty_space = self.empty_space - KiraSize::new_mb(2);
KiraSize::new_mb(2) KiraSize::new_mb(2)
} else { } else {
self.dev.size - self.empty_space // last part end + 1
self.part_list.last().unwrap().next_part_start()
}; };
let (size, start, _) = let (a_size, a_start, _) =
align_part(part_size.b(), part_start.b(), self.dev.sector_size.b()).unwrap(); align_part(part_size.b(), part_start.b(), self.dev.sector_size.b()).unwrap();
log::debug!(
"PartLayout.add_part gpt_label{:?}, size_asked:{}, size_al:{}",
gpt_label,
part_size,
a_size
);
let part_name = format!("{}p{}", self.dev.name, self.part_list.len() + 1); let part_name = format!("{}p{}", self.dev.name, self.part_list.len() + 1);
self.part_list.push(PartInfo { self.part_list.push(PartInfo {
name: part_name, name: part_name,
size: KiraSize::new_b(size), size: KiraSize::new_b(a_size),
start: KiraSize::new_b(start), start: KiraSize::new_b(a_start),
fs_type: fs_type, fs_type: fs_type,
gpt_label: gpt_label, gpt_label: gpt_label,
fs_label: fs_label, fs_label: fs_label,
@@ -410,10 +455,14 @@ impl PartLayout {
role: role, role: role,
}); });
self.empty_space = self.empty_space - KiraSize::new_b(size); self.empty_space = self.empty_space - KiraSize::new_b(a_size);
self self
} }
///
/// Use this to add partition of (disk_empty_space - reserve_space)
/// Specifically to leave some space at the end for SWAP and such
///
pub fn add_part_reserve( pub fn add_part_reserve(
self, self,
reserve_space: KiraSize, reserve_space: KiraSize,
@@ -427,7 +476,13 @@ impl PartLayout {
self.add_part(p_size, fs_type, gpt_label, fs_label, mount_point, role) self.add_part(p_size, fs_type, gpt_label, fs_label, mount_point, role)
} }
pub fn gen_kira_layout(dev: BlkDev, efi_size: KiraSize, swap_size: KiraSize, maybe_password: Option<String>, maybe_compr: Option<String>) -> Self { pub fn gen_kira_layout(
dev: BlkDev,
efi_size: KiraSize,
swap_size: KiraSize,
maybe_password: Option<String>,
maybe_compr: Option<String>,
) -> Self {
let mut res: PartLayout = PartLayout::new(dev); let mut res: PartLayout = PartLayout::new(dev);
// UEFI partition // UEFI partition
@@ -465,7 +520,6 @@ impl PartLayout {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rand::RngExt; use rand::RngExt;
+25 -14
View File
@@ -19,18 +19,25 @@
*/ */
use crate::kira_disk_layout::*; use crate::kira_disk_layout::*;
use std::process::Command; use crate::kira_size::KiraSize;
use std::fs; use std::fs;
use std::process::Command;
#[derive(Debug)] #[derive(Debug)]
pub struct CommandFailed{ pub struct CommandFailed {
stderr: Vec<u8>, stderr: Vec<u8>,
cmd: String, cmd: String,
} }
impl std::fmt::Display for CommandFailed { impl std::fmt::Display for CommandFailed {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Command failed! Command: {}; Stderr: {}", self.cmd, String::from_utf8(self.stderr.clone()).unwrap_or_else(|_|{"STDEER IS NOT VALID UTF-8".to_string()})) write!(
f,
"Command failed! Command: {}; Stderr: {}",
self.cmd,
String::from_utf8(self.stderr.clone())
.unwrap_or_else(|_| { "STDEER IS NOT VALID UTF-8".to_string() })
)
} }
} }
@@ -124,7 +131,10 @@ pub fn dinit_sync_time_chrony() -> Result<(), ExecCommandError> {
/// Install base system /// Install base system
/// basestrap /mnt base base-devel dinit elogind-dinit /// basestrap /mnt base base-devel dinit elogind-dinit
pub fn basestrap_dinit(root_dir: &str) -> Result<(), ExecCommandError> { pub fn basestrap_dinit(root_dir: &str) -> Result<(), ExecCommandError> {
exec_command("basestrap", &vec![root_dir, "base", "base-devel", "dinit", "elogind-dinit"]) exec_command(
"basestrap",
&vec![root_dir, "base", "base-devel", "dinit", "elogind-dinit"],
)
} }
/// Executes parted command with given arguments /// Executes parted command with given arguments
@@ -151,12 +161,7 @@ fn parted_get_last_part_num(dev: &BlkDev) -> Result<u32, ExecCommandError> {
/// Its blocking function /// Its blocking function
pub fn parted_init_gpt_part_table(dev: &BlkDev) -> Result<(), ExecCommandError> { pub fn parted_init_gpt_part_table(dev: &BlkDev) -> Result<(), ExecCommandError> {
let dev_full_name = dev.full_name(); let dev_full_name = dev.full_name();
let args = vec![ let args = vec!["--script", &dev_full_name, "mklabel", "gpt"];
"--script",
&dev_full_name,
"mklabel",
"gpt",
];
exec_command("parted", &args) exec_command("parted", &args)
} }
@@ -166,7 +171,8 @@ const LINUX_ROOT_X86_64_TYPE: &str = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709";
/// It assumes that we add partitions sequentially to empty space (for part attributes settings) /// It assumes that we add partitions sequentially to empty space (for part attributes settings)
/// Otherwise can produce bonkers layout /// Otherwise can produce bonkers layout
pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandError> { pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandError> {
let part_end = part.start + part.size; // important to shift here by 1 because disk index is starting from 0, and part end pointing to last byte of the partition.
let part_end = part.part_end();
// gpt label should be in double qutes // gpt label should be in double qutes
let gpt_label = if let Some(s) = &part.gpt_label { let gpt_label = if let Some(s) = &part.gpt_label {
@@ -174,6 +180,14 @@ pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandErr
} else { } else {
"\"\"".to_string() "\"\"".to_string()
}; };
log::debug!(
"Creatin partition dev:{}, label:{}, fs_type:{}, start:{}, end:{}",
dev.full_name(),
gpt_label,
part.fs_type.to_parted_str(),
part.start.to_parted_bytes_str(),
part_end.to_parted_bytes_str()
);
// creating partition // creating partition
exec_parted(&vec![ exec_parted(&vec![
"--script", "--script",
@@ -255,13 +269,11 @@ pub fn bcachefs_format(
/// unlok encrypted bcache volume /// unlok encrypted bcache volume
pub fn bcachefs_unlock(dev_name: &str, pass: &str) -> Result<(), ExecCommandError> { pub fn bcachefs_unlock(dev_name: &str, pass: &str) -> Result<(), ExecCommandError> {
// bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0 // bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0
let arg = vec!["unlock", "--file=/tmp/bzzpsspass.txt ", dev_name]; let arg = vec!["unlock", "--file=/tmp/bzzpsspass.txt ", dev_name];
// creating tmp file with password // creating tmp file with password
fs::write("/tmp/bzzpsspass.txt", &pass)?; fs::write("/tmp/bzzpsspass.txt", &pass)?;
let out = exec_command("bcachefs", &arg); let out = exec_command("bcachefs", &arg);
// ignore any errors while deleting pass tmp file // ignore any errors while deleting pass tmp file
let _ = fs::remove_file("/tmp/bzzpsspass.txt"); let _ = fs::remove_file("/tmp/bzzpsspass.txt");
@@ -304,7 +316,6 @@ pub fn mkfs_esp(dev: &str) -> Result<(), ExecCommandError> {
mkfs_fat32(dev, Some("ESP")) mkfs_fat32(dev, Some("ESP"))
} }
pub fn mkswap(dev: &str) -> Result<(), ExecCommandError> { pub fn mkswap(dev: &str) -> Result<(), ExecCommandError> {
//mkswap -L SWAP /dev/sda4 //mkswap -L SWAP /dev/sda4
exec_command("mkswap", &vec!["L", "SWAP", dev]) exec_command("mkswap", &vec!["L", "SWAP", dev])