Cannot Boot When changing the BTRFS Subvolume of /boot

Hello!
I’m having a problem with either GRUB or uboot (not sure which) after reconfiguring my flashed debian-12-base-arm64+arm64.img to my eMMC on the aml-s905x-cc-v2 (Sweet Potato).
I am not a fan of installing the root filesystem to the top level subvolume (subvolid=5) in BTRFS. Unfortunetly, debian-12-base-arm64+arm64.img is setup that way. After my first boot, I created 4 subvolumes.

# cd /
# btrfs sub create @
# btrfs sub create @swap
# btrfs sub create @home
# btrfs sub create @snapshots

I turn off swap and unmount /boot/efi
# swapoff -a && umount /boot/efi

I move the swapfile into the @swap subvolume and disable swapfile creation by systemd

# mv /swapfile @swap/
# systemctl disable mkswap.service

I then copy everything except for proc, sys, run, tmp, dev into the new rootfs subvolume (@)
# cp -a <everything> @/

I manually recreate the excluded directories and add a couple others in @ and adjust permissions

# mkdir -p @/{proc,sys,run,tmp,dev,toplevel,snapshots,swap}
# chmod 555 @/{proc,sys}

Fixup /@/etc/fstab in the new rootfs

PARTUUID=186ce4b8-02    /       btrfs   noatime,compress=zstd,x-systemd.growfs,subvol=/@        0       1
PARTUUID=186ce4b8-02    /swap   btrfs   defaults,compress=zstd,subvol=/@swap    0
PARTUUID=186ce4b8-02    /home   btrfs   noatime,compress=zstd,subvol=/@home     0       2
PARTUUID=186ce4b8-02    /snapshots      btrfs   noauto,noatime,compress=zstd,subvol=/@snapshots 0       2
PARTUUID=186ce4b8-02    /toplevel       btrfs   noauto,noatime,compress=zstd,subvolid=5 0       2
PARTUUID=186ce4b8-01    /boot/efi       vfat    defaults        0       1
/swap/swapfile  none    swap    defaults        0       0

Set the new rootfs (@) as the new default subvolume and reboot
# btrfs sub set-default @ && reboot

After reboot, I am in the new rootfs (@) and I re-install and update grub for good measure
# cd / && grub-install --efi-directory=/boot/efi && update-grub

The new /boot/grub/grub.cfg looks like this and note the “/@/boot…” to linux and initrd lines, so it appears Grub is working in the correct rootfs.

#
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#

### BEGIN /etc/grub.d/00_header ###
if [ -s $prefix/grubenv ]; then
  set have_grubenv=true
  load_env
fi
if [ "${next_entry}" ] ; then
   set default="${next_entry}"
   set next_entry=
   save_env next_entry
   set boot_once=true
else
   set default="0"
fi

if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
else
  menuentry_id_option=""
fi

export menuentry_id_option

if [ "${prev_saved_entry}" ]; then
  set saved_entry="${prev_saved_entry}"
  save_env saved_entry
  set prev_saved_entry=
  save_env prev_saved_entry
  set boot_once=true
fi

function savedefault {
  if [ -z "${boot_once}" ]; then
    saved_entry="${chosen}"
    save_env saved_entry
  fi
}
function load_video {
  if [ x$feature_all_video_module = xy ]; then
    insmod all_video
  else
    insmod efi_gop
    insmod efi_uga
    insmod ieee1275_fb
    insmod vbe
    insmod vga
    insmod video_bochs
    insmod video_cirrus
  fi
}

if [ x$feature_default_font_path = xy ] ; then
   font=unicode
else
insmod part_msdos
insmod btrfs
search --no-floppy --fs-uuid --set=root ae802f12-183e-4db5-b8a1-d70eba710416
    font="/@/usr/share/grub/unicode.pf2"
fi

if loadfont $font ; then
  set gfxmode=auto
  load_video
  insmod gfxterm
  set locale_dir=$prefix/locale
  set lang=en_US
  insmod gettext
fi
terminal_output gfxterm
if [ "${recordfail}" = 1 ] ; then
  set timeout=2
else
  if [ x$feature_timeout_style = xy ] ; then
    set timeout_style=menu
    set timeout=2
  # Fallback normal timeout code in case the timeout_style feature is
  # unavailable.
  else
    set timeout=2
  fi
fi
### END /etc/grub.d/00_header ###

### BEGIN /etc/grub.d/05_debian_theme ###
set menu_color_normal=cyan/blue
set menu_color_highlight=white/blue
### END /etc/grub.d/05_debian_theme ###

### BEGIN /etc/grub.d/10_linux ###
function gfxmode {
        set gfxpayload="${1}"
}
set linux_gfx_mode=
export linux_gfx_mode
menuentry 'Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-ae802f12-183e-4db5-b8a1-d70eba710416' {
        load_video
        insmod gzio
        if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
        insmod part_msdos
        insmod btrfs
        search --no-floppy --fs-uuid --set=root ae802f12-183e-4db5-b8a1-d70eba710416
        echo    'Loading Linux 6.1.74-12781-g74961fb0a5d2 ...'
        linux   /@/boot/vmlinuz-6.1.74-12781-g74961fb0a5d2 root=UUID=ae802f12-183e-4db5-b8a1-d70eba710416 ro rootflags=subvol=@  noquiet
        echo    'Loading initial ramdisk ...'
        initrd  /@/boot/initrd.img-6.1.74-12781-g74961fb0a5d2
}
submenu 'Advanced options for Debian GNU/Linux' $menuentry_id_option 'gnulinux-advanced-ae802f12-183e-4db5-b8a1-d70eba710416' {
        menuentry 'Debian GNU/Linux, with Linux 6.1.74-12781-g74961fb0a5d2' --class debian --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.1.74-12781-g74961fb0a5d2-advanced-ae802f12-183e-4db5-b8a1-d70eba710416' {
                load_video
                insmod gzio
                if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
                insmod part_msdos
                insmod btrfs
                search --no-floppy --fs-uuid --set=root ae802f12-183e-4db5-b8a1-d70eba710416
                echo    'Loading Linux 6.1.74-12781-g74961fb0a5d2 ...'
                linux   /@/boot/vmlinuz-6.1.74-12781-g74961fb0a5d2 root=UUID=ae802f12-183e-4db5-b8a1-d70eba710416 ro rootflags=subvol=@  noquiet
                echo    'Loading initial ramdisk ...'
                initrd  /@/boot/initrd.img-6.1.74-12781-g74961fb0a5d2
        }
        menuentry 'Debian GNU/Linux, with Linux 6.1.74-12781-g74961fb0a5d2 (recovery mode)' --class debian --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.1.74-12781-g74961fb0a5d2-recovery-ae802f12-183e-4db5-b8a1-d70eba710416' {
                load_video
                insmod gzio
                if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
                insmod part_msdos
                insmod btrfs
                search --no-floppy --fs-uuid --set=root ae802f12-183e-4db5-b8a1-d70eba710416
                echo    'Loading Linux 6.1.74-12781-g74961fb0a5d2 ...'
                linux   /@/boot/vmlinuz-6.1.74-12781-g74961fb0a5d2 root=UUID=ae802f12-183e-4db5-b8a1-d70eba710416 ro single rootflags=subvol=@ 
                echo    'Loading initial ramdisk ...'
                initrd  /@/boot/initrd.img-6.1.74-12781-g74961fb0a5d2
        }
}

### END /etc/grub.d/10_linux ###

### BEGIN /etc/grub.d/20_linux_xen ###
### END /etc/grub.d/20_linux_xen ###

### BEGIN /etc/grub.d/30_os-prober ###
### END /etc/grub.d/30_os-prober ###

### BEGIN /etc/grub.d/30_uefi-firmware ###
menuentry 'UEFI Firmware Settings' $menuentry_id_option 'uefi-firmware' {
        fwsetup
}
### END /etc/grub.d/30_uefi-firmware ###

### BEGIN /etc/grub.d/40_custom ###
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
### END /etc/grub.d/40_custom ###

### BEGIN /etc/grub.d/41_custom ###
if [ -f  ${config_directory}/custom.cfg ]; then
  source ${config_directory}/custom.cfg
elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
  source $prefix/custom.cfg
fi
### END /etc/grub.d/41_custom ###

I then mount the toplevel subvolume (subvolid=5) and delete everything except my subvolumes

# cd /toplevel
# rm -fr <everything> ./
# ls -lah /toplevel
drwxr-xr-x 1 root root  50 Dec 18 20:27 .
drwxr-xr-x 1 root root 164 Jan 23  2024 ..
drwxr-xr-x 1 root root 164 Jan 23  2024 @
drwxr-xr-x 1 root root  16 Dec 19 07:35 @home
drwxr-xr-x 1 root root   0 Dec 18 20:18 @snapshots
drwxr-xr-x 1 root root  16 Dec 18 20:21 @swap

I unmount the toplevel and for good measure, I re-run update-grub

# umount /toplevel
# update-grub

Then upon reboot, I’m dropped to the grub command line. :frowning:
I start over and instead of deleting everything except my subvolumes, I also keep the boot directory in subvolid=5 and reboot. This time, I am able to successfully boot. When I delete boot from subvolid=5, I’m dropped to the Grub command line again. So, what am I missing? How can I get Grub (or is it u-boot?) to look at the correct subvolume for the correct root filesystem with /boot?

Here’s my early boot sequence and u-boot enviornment

system cmd  1.
GXL:BL1:9ac50e:bb16dc;FEAT:ADFC318C:0;POC:1;RCY:0;SPI:0;0.0;CHK:0;
TE: 35060

BL2 Built : 15:21:18, Aug 28 2019. gxl g1bf2b53 - luan.yuan@droid15-sz

set vcck to 1120 mv
set vddee to 1000 mv
Board ID = 4
CPU clk: 1200MHz
DDR enable rdbi
DQS-corr enabled
DDR scramble enabled
DDR4 chl: Rank0 @ 1080MHz

bist_test rank: 0 14 00 28 28 19 37 12 00 25 2d 22 38 14 00 29 2a 1c 39 12 00 24 27 1b 33 723
Rank0: 2048MB(auto)-2T-18
AddrBus test pass!
Load fip header from SPI, src: 0x0000c000, des: 0x01400000, size: 0x00004000, part: 0
New fip structure!
Load bl30 from SPI, src: 0x00010000, des: 0x013c0000, size: 0x0000d600, part: 0
Load bl31 from SPI, src: 0x00020000, des: 0x05100000, size: 0x0001b800, part: 0
Load bl33 from SPI, src: 0x0003c000, des: 0x01000000, size: 0x00094200, part: 0
NOTICE:  BL31: v1.3(release):c3714b49be
NOTICE:  BL31: Built : 09:23:36, Jun 20 2023. gxl bl-3.5.0 gc3714b49be - jenkins@walle02-sh
NOTICE:  BL3-1: GXL normal boot!
NOTICE:  BL31: BL33 decompress pass
mpu_config_enable:system pre init ok
OPS=0x84
dmc sec lock
[Image: gxl_v1.1.3509-d977ed20a4 2023-06-20 09:43:46 jenkins@walle02-sh]
21 0d 84 00 72 0d d7 ea ae 6c bc 94 d3 d1 4b 08
[0.782528 Inits done]
secure task start!
high task start!
low task start!
ERROR:   Error initializing runtime service opteed_fast


U-Boot 2023.07+ (May 15 2024 - 23:34:17 -0400) Libre Computer AML-S905X-CC-V2

Model: Libre Computer AML-S905X-CC V2
SoC:   Amlogic Meson GXL (S905X) Revision 21:d (84:2)
DRAM:  2 GiB
Core:  187 devices, 35 uclasses, devicetree: separate
WDT:   Not starting watchdog@98d0
MMC:   mmc@72000: 1, mmc@74000: 0
Loading Environment from FAT... OK
Error (-2): cannot determine file size
[BL31]: tee size: 0
Net:   eth0: ethernet@c9410000
starting USB...
Bus usb@c9000000: dwc3_meson_gxl_get_phys: usb2 ports: 2
Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.00
scanning bus usb@c9000000 for devices... 2 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  0
=> env print
arch=arm
autoload=0
baudrate=115200
board=aml-s905x-cc-v2
board_name=aml-s905x-cc-v2
boot_source=spi
boot_targets=usb mmc1 mmc0 spi
bootcmd=bootflow scan -lb
bootdelay=1
bootdevice=0
cpu=armv8
ethaddr=8e:99:d3:76:2a:0c
fdt_addr_r=0x08008000
fdtcontroladdr=75e86ee0
fdtfile=amlogic/meson-gxl-s905x-libretech-cc-v2.dtb
fdtoverlay_addr_r=0x01000000
kernel_addr_r=0x08080000
kernel_comp_addr_r=0x0d080000
kernel_comp_size=0x2000000
loadaddr=0x1000000
preboot=usb start
pxefile_addr_r=0x01080000
ramdisk_addr_r=0x13000000
scriptaddr=0x08000000
soc=meson
splashdevpart=0
splashfile=boot.bmp
splashimage=0x1000000
splashpos=m,m
splashsource=mmc_fs
stderr=vidconsole,serial
stdin=usbkbd,serial
stdout=vidconsole,serial
vendor=libre-computer
ver=U-Boot 2023.07+ (May 15 2024 - 23:34:17 -0400) Libre Computer AML-S905X-CC-V2

Environment size: 816/4092 bytes

I moved my efi partition mount to the top level subvolume (subvolid=5) and then used a bind mount for boot in the top level that points to /@/boot I then reinstalled grub to point at the new efi directory and I can still boot the board.

# ls -lah /toplevel/
total 32K
drwxr-xr-x 1 root root  56 Dec 20 08:56 .
drwxr-xr-x 1 root root 164 Jan 23  2024 ..
drwxr-xr-x 1 root root 164 Jan 23  2024 @
drwxr-xr-x 1 root root 572 Dec 20 09:00 boot
drwxr-xr-x 3 root root 16K Dec 31  1969 efi
drwxr-xr-x 1 root root  16 Dec 19 07:35 @home
drwxr-xr-x 1 root root   0 Dec 18 20:18 @snapshots
drwxr-xr-x 1 root root  16 Dec 19 20:11 @swap
# grub-install --efi-directory=/toplevel/efi
# cat /etc/fstab
PARTUUID=186ce4b8-02    /       btrfs   noatime,compress=zstd,x-systemd.growfs,subvol=/@        0       1
PARTUUID=186ce4b8-02    /swap   btrfs   defaults,compress=zstd,subvol=/@swap    0
PARTUUID=186ce4b8-02    /home   btrfs   noatime,compress=zstd,subvol=/@home     0       2
PARTUUID=186ce4b8-02    /snapshots      btrfs   noatime,compress=zstd,subvol=/@snapshots        0       2
PARTUUID=186ce4b8-02    /toplevel       btrfs   noatime,compress=zstd,subvolid=5        0       2
PARTUUID=186ce4b8-01    /toplevel/efi   vfat    defaults        0       1
/swap/swapfile  none    swap    defaults        0       0
/boot   /toplevel/boot  none    bind    0       0

It would be nice to have boot and efi mount point under @, but this is working. Is there a way to get boot and the efi mount point under @?