Multi-boot partitioning / Shared GRUB partition
The original problem
The first /boot was a 1G partition. Arch’s kernel packages fill it faster than intuition suggests: linux and linux-lts kernels each carry a compressed kernel image and an initramfs, plus fallback initramfs. Headers add more. Two kernels with headers and both initramfs images consume the better part of 900MB. A single update can tip the partition from 80% to 100% full.
The short-term fix was managing it manually — dropping old kernel packages before updates. The correct fix was a larger partition and a design that accounts for two distros writing into the same /boot.
p8 is now 7.6G with UUID fba989bd-2a90-4e11-9aa2-4c941d3e0460. Both Void and Arch mount it at /boot. Neither distro runs out of space under any realistic kernel rotation.
Why ext4 for /boot
btrfs is valid for /boot if GRUB is compiled with btrfs support and the subvolume layout is simple. In practice, GRUB’s btrfs support has historically been fragile — it cannot read compressed files and has limitations with certain subvolume configurations. Using ext4 for /boot removes that variable. GRUB reads ext4 reliably.
The choice also matters for the symlink issue described below.
GRUB ownership
Two distros, one GRUB. The alternative — each distro installing and maintaining its own GRUB — produces conflicting EFI entries and competing update-grub calls that overwrite each other’s configuration. The cleaner architecture is one distro owning GRUB entirely.
Arch owns GRUB here. The EFI entry points to Arch’s GRUB binary in the ESP. GRUB reads its configuration from /boot/grub/grub.cfg, which is on p8.
Void does not install GRUB. It does not create an EFI entry. It does not run grub-mkconfig. Its kernel appears in GRUB’s menu only because Arch’s GRUB config includes it as a custom entry.
The grub-install mistake
During Void’s installation, grub-install --bootloader-id=void was run inside the chroot. This created a second EFI entry (0004) pointing to /boot/efi/EFI/void/grubx64.efi. The Arch GRUB entry was still present but the EFI boot order had changed.
Cleanup required two steps:
# remove the EFI boot entry
efibootmgr -b 0004 -B
# remove the EFI directory
rm -rf /boot/efi/EFI/void
The lesson: in a shared-GRUB setup, the non-owning distro should not run grub-install at all, and its fstab should mount the ESP read-only or not mount it at all.
The 40_custom architecture
GRUB’s /etc/grub.d/ directory contains numbered scripts that generate sections of grub.cfg. The standard scripts include:
10_linux— detects kernels in/booton the current distro30_os-prober— scans for other operating systems40_custom— static entries written by hand
On the Arch installation, 10_linux is disabled:
chmod -x /etc/grub.d/10_linux
Without this, grub-mkconfig generates duplicate entries — one from 10_linux’s auto-detection and one from 40_custom. The manual entries in 40_custom are explicit and complete; auto-detection adds nothing.
The Void and Arch entries in 40_custom:
menuentry "Void Linux" {
insmod part_gpt
insmod btrfs
insmod ext2
set root='hd0,gpt8'
linux /vmlinuz-6.12.81_1 root=UUID=d7a98795-1604-4baa-ae07-05e29a3ff1e6 rootflags=subvol=@void rw quiet
initrd /initramfs-6.12.81_1.img
}
menuentry "Arch Linux" {
insmod part_gpt
insmod btrfs
set root='hd0,gpt8'
linux /vmlinuz-linux root=UUID=275bce6c-f037-43f9-be0f-650efb12cf1e rootflags=subvol=@ rw quiet
initrd /initrd.img-linux
}
The symlink trap
Linux distributions commonly create symlinks in /boot for convenience:
/boot/vmlinuz -> vmlinuz-6.12.81_1
/boot/initrd.img -> initramfs-6.12.81_1.img
GRUB on ext4 does not follow symlinks. A linux /vmlinuz entry in grub.cfg will fail to find the file because GRUB’s ext4 driver reads directory entries, not symlink targets.
This means 40_custom must reference exact filenames:
linux /vmlinuz-6.12.81_1
initrd /initramfs-6.12.81_1.img
When Void updates its kernel, the filename changes. The 40_custom entry becomes stale and GRUB will fail to boot Void until the config is updated and grub-mkconfig is run on Arch.
The correct mitigation is a kernel post-install hook on Void that updates the filenames in 40_custom and triggers grub-mkconfig. Without the hook, a kernel update is a two-step manual process. See [Multi-boot partitioning / Maintenance] for the hook design.
os-prober and GRUB_OS_PROBER_SKIP_LIST
os-prober scans mounted and unmountable filesystems for other operating systems and generates menu entries for them. When /boot is shared between distros, os-prober finds Void’s kernels on the ext4 partition and generates entries — which are broken because os-prober’s entries don’t carry the correct rootflags=subvol=@void parameter needed for btrfs root.
The fix:
# /etc/default/grub
GRUB_OS_PROBER_SKIP_LIST="d7a98795-1604-4baa-ae07-05e29a3ff1e6@/dev/nvme0n1p5"
This tells os-prober to skip p5 entirely. Windows is still detected by os-prober (from its own ntfs partition) and gets a correct entry. Void is handled exclusively through 40_custom.
Connection closed. Returning to terminal...