This commit is contained in:
Hadi Chokr
2026-04-05 11:38:39 +02:00
parent 116f010adb
commit e59a35de86
5 changed files with 98 additions and 10 deletions

View File

@@ -122,7 +122,7 @@ fn run(root: &Path) -> Result<(), Box<dyn Error>> {
println!(
"Found {concerning_fstab_entries} concerning fstab entries. This suggests you have a more complicated fstab setup that we cannot auto-migrate. \
If nothing critically important is managed by fstab you can let the auto-migration run. If you have entries that are required for the system to boot you should manually migrate to @system."
If nothing critically important is managed by fstab you can let the auto-migration run. If you have entries that are required for the system to boot you should manually migrate to @system."
);
io::stdout().flush().unwrap();
@@ -170,9 +170,9 @@ fn run(root: &Path) -> Result<(), Box<dyn Error>> {
defer! {
println!("Unmounting overlay for {}", dir);
Command::new("umount")
.arg(&compose_dir)
.status()
.expect("Failed to unmount overlay for etc/var");
.arg(&compose_dir)
.status()
.expect("Failed to unmount overlay for etc/var");
}
println!(
@@ -237,6 +237,55 @@ fn run(root: &Path) -> Result<(), Box<dyn Error>> {
return Ok(());
}
fn run_v3(root: &Path) -> Result<(), Box<dyn Error>> {
let system_home = root.join("@system/home");
let system_home_tmp = root.join("@system/home.v3tmp");
let _ = Command::new("plymouth")
.arg("display-message")
.arg("--text=Migrating to v3 rootfs. Can take a while.")
.status();
println!("Migrating @system/home from subvolume to regular directory with per-user subvolumes");
// Stage into a sibling directory so that if we crash mid-way, @system/home is still a subvolume
// and the next boot will retry the migration cleanly.
fs::create_dir(&system_home_tmp)?;
for entry in fs::read_dir(&system_home)? {
let entry = entry?;
let src = entry.path();
if !src.is_dir() {
continue;
}
let dst = system_home_tmp.join(entry.file_name());
println!("Creating user subvolume at {dst:?}");
CreateSubvolumeOptions::new()
.create(&dst)
.map_err(|e| format!("Failed to create subvolume {dst:?}: {e:?}"))?;
let cp_result = Command::new("cp")
.arg("--recursive")
.arg("--archive")
.arg("--reflink=auto")
.arg(format!("{}/.", src.display()))
.arg(format!("{}/.", dst.display()))
.status()
.expect("Failed to copy user home");
if !cp_result.success() {
return Err(format!("Failed to copy {src:?} to {dst:?}").into());
}
}
DeleteSubvolumeOptions::new()
.delete(&system_home)
.map_err(|e| format!("Failed to delete @system/home subvolume: {e:?}"))?;
println!("Renaming {system_home_tmp:?} to {system_home:?}");
fs::rename(&system_home_tmp, &system_home)?; // fatal problem
return Ok(());
}
fn main() -> Result<(), Box<dyn Error>> {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
@@ -245,11 +294,22 @@ fn main() -> Result<(), Box<dyn Error>> {
return Err("Not enough arguments".into());
}
println!("Migrating to v2 rootfs. This will take a while.");
let root = Path::new(&args[1]);
let system_path = root.join("@system");
match run(root) {
let (msg, result) = if system_path.exists() {
println!("Migrating to v3 rootfs.");
(
"Migrating to v3 rootfs. This will take a while.",
run_v3(root),
)
} else {
println!("Migrating to v2 rootfs. This will take a while.");
("Migrating to v2 rootfs. This will take a while.", run(root))
};
let _ = msg; // used for context above
match result {
Ok(_) => {
// Reactivate in case we deactivated it earlier
let _ = Command::new("plymouth").arg("show-splash").status();

View File

@@ -90,7 +90,8 @@ btrfs subvolume sync . || true
btrfs quota enable --simple .
btrfs subvolume create @system
btrfs subvolume create @system/etc
mkdir @system/boot @system/proc @system/sys @system/dev @system/run @system/usr
btrfs subvolume delete @system/home || true
mkdir @system/boot @system/proc @system/sys @system/dev @system/run @system/usr @system/home
cp /dev/gpt-auto-root kde-linux_$IMAGE_VERSION.erofs
# Overmount calamares' mount with the subvol mount

View File

@@ -24,8 +24,14 @@ mount -o rw,subvol=/ /dev/gpt-auto-root /run/kde-linux-rootfs-transition
# In a way we could think about moving the mounts into a generator TBH. Then we can do proper condition management on
# the systemd side. Question is if they get correctly unmounted automatically.
if [ -e /run/kde-linux-rootfs-transition/@system ]; then
cd /
umount --recursive --lazy /run/kde-linux-rootfs-transition
# v2->v3: @system/home is a btrfs subvolume but should be a regular directory.
if btrfs subvolume show /run/kde-linux-rootfs-transition/@system/home >/dev/null 2>&1; then
/usr/lib/btrfs-migrator /run/kde-linux-rootfs-transition
umount --recursive --lazy /run/kde-linux-rootfs-transition
else
cd /
umount --recursive --lazy /run/kde-linux-rootfs-transition
fi
exit 0
fi

View File

@@ -177,3 +177,17 @@ rm -rf \
rm -rf \
/buildroot \
/.cache \
# Custom Plasma Setup
git clone https://invent.kde.org/plasma/plasma-setup.git
cd plasma-setup
git checkout work/hadi/btrfs
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
make
make install
cd ../
cd ../
rm -rf plasma-setup

View File

@@ -127,6 +127,13 @@ sed -i 's%^SHELL=/usr/bin/bash%SHELL=/usr/bin/zsh%' /etc/default/useradd
# Put new users in sambashare group
sed -i 's%^GROUP=users%GROUP=users\nGROUPS=sambashare%' /etc/default/useradd
# Set BTRFS_SUBVOLUME_HOME for new users
if grep -q '^BTRFS_SUBVOLUME_HOME=' /etc/default/useradd; then
sed -i 's%^BTRFS_SUBVOLUME_HOME=.*%BTRFS_SUBVOLUME_HOME=yes%' /etc/default/useradd
else
echo 'BTRFS_SUBVOLUME_HOME=yes' >> /etc/default/useradd
fi
# Our Plymouth Theme
KEEP_THEME="breeze-bgrt"