From 3fcc781fdd88c05da4572220e01f8703f24c7d79 Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Mon, 14 Sep 2026 07:54:23 -0300 Subject: [PATCH] fix(xcat-core): grub2 cannot load the Ubuntu 26.04 ppc64el netboot initrd The ubuntu-26.04-ppc64el diskless node never starts its kernel. SLOF reports W3411 and E3406 and falls through to disk. The node fetches the kernel and the initrd in under a minute and fails six minutes later, with no network activity in between: grub2 has the payload and cannot start it. genimage copies the whole lib/firmware tree of the root image into the initrd. That tree is 666 MB on Ubuntu 26.04, which takes the initrd to 719 MB. A 687 MB initrd boots the same kernel on the same node; a 719 MB one does not. The firmware copy now takes only the firmware that the drivers in the initrd ask for, which modinfo reports for each module. The root image keeps its whole tree, so the node that boots is unchanged. ubuntu_genimage_initrd_firmware.t drives the firmware step over a root image whose firmware tree holds files no driver asks for. It fails on the previous commit. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- .../share/xcat/netboot/ubuntu/genimage | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/xCAT-server/share/xcat/netboot/ubuntu/genimage b/xCAT-server/share/xcat/netboot/ubuntu/genimage index 17005cdb5..9fe0803b4 100755 --- a/xCAT-server/share/xcat/netboot/ubuntu/genimage +++ b/xCAT-server/share/xcat/netboot/ubuntu/genimage @@ -1827,8 +1827,11 @@ EOMS } } - if (-d "$rootimg_dir/lib/firmware/") { - system("cp -r $rootimg_dir/lib/firmware/* /tmp/xcatinitrd.$$/lib/firmware"); + # The whole firmware tree is 666 MB on Ubuntu 26.04, and grub2 on a pseries node cannot + # load an initrd of that size. The initrd only has to reach the network. + foreach my $firmware (initrd_firmware_files($rootimg_dir, \@filestoadd)) { + copy_initrd_file("$rootimg_dir/lib/firmware/$firmware", + "/tmp/xcatinitrd.$$/lib/firmware/$firmware"); } if (-d "$rootimg_dir/lib/modules/$kernelver/") { @@ -1892,6 +1895,55 @@ sub isnetdriver { } } +#------------------------------------------------------------------------------- + +=head3 initrd_firmware_files + + Descriptions: Select the firmware that the drivers in the netboot initrd ask for. + Arguments: + rootimg_dir - the root image directory + filestoadd - reference to the list of files that go into the initrd. A module + is either a plain path or a [ source, destination ] pair. + Returns: the firmware files that exist, as paths below lib/firmware + +=cut + +#------------------------------------------------------------------------------- +sub initrd_firmware_files { + my ($rootimg_dir, $filestoadd) = @_; + + return () unless (-d "$rootimg_dir/lib/firmware"); + + my %wanted; + foreach my $entry (@$filestoadd) { + my $module = ref($entry) ? $entry->[0] : $entry; + next unless ($module =~ /\.ko(?:\.(?:gz|xz|zst))?$/); + next unless (-f "$rootimg_dir/$module"); + + my $out = `modinfo -F firmware "$rootimg_dir/$module" 2>/dev/null`; + if ($?) { + print "Warning: cannot read the firmware of $module\n"; + next; + } + foreach my $name (split(/\n/, $out)) { + $name =~ s/^\s+|\s+$//g; + $wanted{$name} = 1 if (length $name); + } + } + + my @files; + foreach my $name (sort keys %wanted) { + + # Ubuntu keeps the firmware compressed and the kernel asks for the plain name. + foreach my $candidate ($name, "$name.zst", "$name.xz", "$name.gz") { + next unless (-e "$rootimg_dir/lib/firmware/$candidate"); + push @files, $candidate; + last; + } + } + return @files; +} + sub find_rootimg_file { my ($file) = @_;