11{{ $sectorsize := or .sectorsize 512 }}
2- {{ $imagesize := or .imagesize "4GiB" }}
3- {{ $kerneldir := or .kerneldir "prebuilt/linux" }}
4- {{ $cmdline := or .cmdline "audit=0 console=tty1 console=ttyS0,1500000n8" }}
2+ {{ $imagesize := or .imagesize "4GiB" }}
3+ {{ $kerneldir := or .kerneldir "prebuilt/linux" }}
4+ {{ $cmdline := or .cmdline "audit=0 console=tty1 console=ttyS0,1500000n8" }}
5+ {{ $fslabel := or .fslabel "flipperos" }}
6+ {{- /* fs-wide btrfs mount options. ssd is FORCED (loopback/eMMC isn't reliably
7+ detected as non-rotational). */ -}}
8+ {{ $btrfsopts := or .btrfsopts "compress=zstd,noatime,ssd,discard=async" }}
9+ {{ $rootdev := "findmnt -fn --nofsroot -o SOURCE --target $IMAGEMNTDIR" }}
510
611architecture : arm64
712sectorsize : {{ $sectorsize }}
8-
913actions :
1014 - action : unpack
1115 description : Load a tarball of the root filesystem
1216 file : debian-ospack.tar.gz
1317
18+ # debos formats btrfs (default flags, random FSUUID), mounts the top level at
19+ # $IMAGEMNTDIR, and records the standard root fstab line + root=UUID.
20+ # fsck:false -> passno 0 (no boot-time fsck for btrfs).
1421 - action : image-partition
1522 imagename : debian-nobootloader.img
1623 imagesize : {{ $imagesize }}
@@ -22,20 +29,74 @@ actions:
2229 end : 64MiB
2330 - name : root
2431 fs : btrfs
32+ fslabel : {{ $fslabel }}
33+ fsck : false
2534 start : 64MiB
2635 end : -1MiB
2736 mountpoints :
2837 - mountpoint : /
2938 partition : root
30- options : [ compress=zstd, x-systemd.growfs ]
39+ options : [ compress=zstd, noatime, ssd, discard=async, x-systemd.growfs ]
3140
41+ # Subvolume layout (no reformat). /boot is a TOP-LEVEL subvolume named "boot"
42+ # (not "@boot") so it sits outside @ -> a single shared /boot that root snapshots
43+ # never capture, and so U-Boot, which reads the default (top-level) subvolume,
44+ # resolves /boot/extlinux/... straight into it. Keep the default subvolume as the
45+ # top level (do NOT set-default @) or U-Boot won't see this sibling /boot.
3246 - action : run
33- description : Enable zstd compression on the image mount
47+ description : Create subvolumes and mount the layout
3448 chroot : false
35- command : mount -o remount,compress=zstd "$IMAGEMNTDIR"
49+ command : |
50+ set -eu
51+ ROOTPART="$({{ $rootdev }})"
52+
53+ # debos has the top level (subvolid=5) mounted here; create subvolumes on it.
54+ for sv in @ boot @home @snapshots @var-log @var-cache; do
55+ btrfs subvolume create "$IMAGEMNTDIR/$sv"
56+ done
57+ umount "$IMAGEMNTDIR"
58+
59+ # Mount @ at the mount point debos owns, then nest the rest under it.
60+ mount -t btrfs -o "{{ $btrfsopts }},subvol=@" "$ROOTPART" "$IMAGEMNTDIR"
61+ mkdir -p "$IMAGEMNTDIR/boot" \
62+ "$IMAGEMNTDIR/home" \
63+ "$IMAGEMNTDIR/.snapshots" \
64+ "$IMAGEMNTDIR/var/log" \
65+ "$IMAGEMNTDIR/var/cache"
66+ mount -t btrfs -o "{{ $btrfsopts }},subvol=boot" "$ROOTPART" "$IMAGEMNTDIR/boot"
67+ # Keep /boot uncompressed so U-Boot can read the kernel/dtb/initrd regardless
68+ # of whether its btrfs driver was built with zstd support. The property is
69+ # stored on the subvolume and inherited by files added later (kernel updates).
70+ btrfs property set "$IMAGEMNTDIR/boot" compression none
71+ mount -t btrfs -o "{{ $btrfsopts }},subvol=@home" "$ROOTPART" "$IMAGEMNTDIR/home"
72+ # @snapshots is mounted only for the build (to write the Factory Image); it's
73+ # not in fstab, so the .snapshots mountpoint is removed from @ before detach.
74+ mount -t btrfs -o "{{ $btrfsopts }},subvol=@snapshots" "$ROOTPART" "$IMAGEMNTDIR/.snapshots"
75+ mount -t btrfs -o "{{ $btrfsopts }},subvol=@var-log" "$ROOTPART" "$IMAGEMNTDIR/var/log"
76+ mount -t btrfs -o "{{ $btrfsopts }},subvol=@var-cache" "$ROOTPART" "$IMAGEMNTDIR/var/cache"
3677
78+ # debos writes the standard root line into /etc/fstab and root=UUID into the
79+ # cmdline; the root subvolume is selected by the appended rootflags=subvol=@.
3780 - action : filesystem-deploy
38- append-kernel-cmdline : {{ $cmdline }}
81+ append-kernel-cmdline : rootflags=subvol=@ {{ $cmdline }}
82+
83+ # Add fstab entries for the non-root subvolumes (debos only generated the root
84+ # line). The FSUUID is read back at build time. @snapshots is intentionally
85+ # omitted -- it holds the Factory Image and is mounted on demand for rollback,
86+ # never auto-mounted at runtime.
87+ - action : run
88+ description : Append subvolume entries to /etc/fstab
89+ chroot : false
90+ command : |
91+ set -eu
92+ ROOTPART="$({{ $rootdev }})"
93+ FSUUID="$(blkid -o value -s UUID -p -c none "$ROOTPART")"
94+ cat >> "$IMAGEMNTDIR/etc/fstab" <<EOF
95+ UUID=$FSUUID /boot btrfs {{ $btrfsopts }},subvol=boot 0 0
96+ UUID=$FSUUID /home btrfs {{ $btrfsopts }},subvol=@home 0 0
97+ UUID=$FSUUID /var/log btrfs {{ $btrfsopts }},subvol=@var-log 0 0
98+ UUID=$FSUUID /var/cache btrfs {{ $btrfsopts }},subvol=@var-cache 0 0
99+ EOF
39100
40101 - action : overlay
41102 description : Copy Linux kernel packages into the target
@@ -47,4 +108,18 @@ actions:
47108 description : Install Linux kernel packages inside the target
48109 chroot : true
49110 command : find /var/cache/linux-kernel -name linux-image-\*.deb -a ! -name \*-dbg_\* -print0 | xargs -0 apt install -y
50-
111+
112+ # Unmount the nested subvolumes (deepest first), leaving @ mounted at
113+ # $IMAGEMNTDIR. debos' image-partition Cleanup unmounts @ and detaches the loop;
114+ # without this it would fail with EBUSY on the still-mounted children.
115+ - action : run
116+ description : Unmount nested subvolumes before debos detaches the loop
117+ chroot : false
118+ command : |
119+ set -eu
120+ sync
121+ findmnt -rno TARGET --submounts "$IMAGEMNTDIR" \
122+ | awk -v root="$IMAGEMNTDIR" '$0 != root' \
123+ | awk '{ print length, $0 }' | sort -rn | cut -d" " -f2- \
124+ | while read -r mp; do umount "$mp"; done
125+ rmdir "$IMAGEMNTDIR/.snapshots"
0 commit comments